SERVER-106496 Update vendored libmongocrypt to 1.15.0 (#39707)

GitOrigin-RevId: 1fb827a0ab5ab338afaf5a650debd07f21818183
This commit is contained in:
Erwin Pe 2025-08-06 17:32:14 -04:00 committed by MongoDB Bot
parent 947af54dcf
commit a397e38c0e
11 changed files with 590 additions and 29 deletions

View File

@ -1171,7 +1171,7 @@
"author": "MongoDB, Inc.",
"group": "mongodb",
"name": "libmongocrypt",
"version": "1.14.0",
"version": "1.15.0",
"description": "Required C library for Client Side and Queryable Encryption in MongoDB",
"licenses": [
{
@ -1181,8 +1181,8 @@
}
],
"copyright": "Copyright 2019-present MongoDB, Inc.",
"cpe": "cpe:2.3:a:mongodb:libmongocrypt:1.14.0:*:*:*:*:*:*:*",
"purl": "pkg:github/mongodb/libmongocrypt@1.14.0",
"cpe": "cpe:2.3:a:mongodb:libmongocrypt:1.15.0:*:*:*:*:*:*:*",
"purl": "pkg:github/mongodb/libmongocrypt@1.15.0",
"properties": [
{
"name": "internal:team_responsible",

View File

@ -101,6 +101,7 @@ mongo_cc_library(
"dist/src/mc-schema-broker.c",
"dist/src/mc-str-encode-string-sets.c",
"dist/src/mc-text-search-str-encode.c",
"dist/src/mc-textopts.c",
"dist/src/mc-tokens.c",
"dist/src/mc-writer.c",
"dist/src/mongocrypt.c",

View File

@ -268,12 +268,14 @@ void mc_FLE2IndexedEncryptedValueV2_destroy(mc_FLE2IndexedEncryptedValueV2_t *ie
_mongocrypt_buffer_cleanup(&iev->ServerEncryptedValue);
_mongocrypt_buffer_cleanup(&iev->S_KeyId);
for (uint32_t i = 0; i < iev->edge_count; i++) {
mc_FLE2TagAndEncryptedMetadataBlock_cleanup(&iev->metadata[i]);
}
if (iev->metadata) {
for (uint32_t i = 0; i < iev->edge_count; i++) {
mc_FLE2TagAndEncryptedMetadataBlock_cleanup(&iev->metadata[i]);
}
// Metadata array is dynamically allocated
bson_free(iev->metadata);
// Metadata array is dynamically allocated
bson_free(iev->metadata);
}
bson_free(iev);
}

View File

@ -0,0 +1,79 @@
/*
* Copyright 2025-present MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MC_TEXTOPTS_PRIVATE_H
#define MC_TEXTOPTS_PRIVATE_H
#include <bson/bson.h>
#include "mc-optional-private.h"
#include "mongocrypt-private.h"
typedef struct {
bool set;
mc_optional_int32_t strMaxLength;
int32_t strMinQueryLength;
int32_t strMaxQueryLength;
} mc_TextOptsPerIndex_t;
typedef struct {
mc_TextOptsPerIndex_t substring;
mc_TextOptsPerIndex_t prefix;
mc_TextOptsPerIndex_t suffix;
bool caseSensitive;
bool diacriticSensitive;
} mc_TextOpts_t;
/* mc_TextOpts_parse parses a BSON document into mc_TextOpts_t.
* The document is expected to have the form:
* {
* "caseSensitive": bool,
* . "diacriticSensitive": bool,
* . "prefix": {
* . "strMaxQueryLength": Int32,
* . "strMinQueryLength": Int32,
* . },
* . "suffix": {
* . "strMaxQueryLength": Int32,
* . "strMinQueryLength": Int32,
* . },
* . "substring": {
* . "strMaxLength": Int32,
* . "strMaxQueryLength": Int32,
* . "strMinQueryLength": Int32,
* . },
* }
*/
bool mc_TextOpts_parse(mc_TextOpts_t *txo, const bson_t *in, mongocrypt_status_t *status);
/*
* mc_TextOpts_to_FLE2TextSearchInsertSpec creates a placeholder value to be
* encrypted. It is only expected to be called when query_type is unset. The
* output FLE2TextSearchInsertSpec is a BSON document of the form:
* https://github.com/mongodb/mongo/blob/219e90bfad3c712c9642da29ee52229908f06bcd/src/mongo/crypto/fle_field_schema.idl#L689
*
* v is expect to be a BSON document of the form:
* { "v": BSON value to encrypt }.
*
* Preconditions: out must be initialized by caller.
*/
bool mc_TextOpts_to_FLE2TextSearchInsertSpec(const mc_TextOpts_t *txo,
const bson_t *v,
bson_t *out,
mongocrypt_status_t *status);
#endif // MC_TEXTOPTS_PRIVATE_H

View File

@ -0,0 +1,339 @@
/*
* Copyright 2025-present MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mc-textopts-private.h"
#include "mongocrypt-private.h"
#include "mongocrypt-util-private.h" // mc_bson_type_to_string
#include "mongocrypt.h"
#include <bson/bson.h>
// Common logic for testing field name, tracking duplication, and presence.
#define IF_FIELD(Name) \
if (0 == strcmp(field, #Name)) { \
if (has_##Name) { \
CLIENT_ERR(ERROR_PREFIX "Unexpected duplicate field '" #Name "'"); \
return false; \
} \
has_##Name = true; \
((void)0)
#define END_IF_FIELD \
continue; \
} \
else((void)0)
#define ERROR_PREFIX "Error parsing TextOpts: "
bool mc_TextOptsPerIndex_parse(mc_TextOptsPerIndex_t *txio, bson_iter_t *iter, mongocrypt_status_t *status) {
*txio = (mc_TextOptsPerIndex_t){0};
txio->set = true;
bool has_strMaxLength = false, has_strMinQueryLength = false, has_strMaxQueryLength = false;
while (bson_iter_next(iter)) {
const char *field = bson_iter_key(iter);
BSON_ASSERT(field);
IF_FIELD(strMaxLength);
{
if (!BSON_ITER_HOLDS_INT32(iter)) {
CLIENT_ERR(ERROR_PREFIX "'strMaxLength' must be an int32");
return false;
}
const int32_t val = bson_iter_int32(iter);
if (val <= 0) {
CLIENT_ERR(ERROR_PREFIX "'strMaxLength' must be greater than zero");
return false;
}
txio->strMaxLength = OPT_I32(val);
}
END_IF_FIELD;
IF_FIELD(strMinQueryLength);
{
if (!BSON_ITER_HOLDS_INT32(iter)) {
CLIENT_ERR(ERROR_PREFIX "'strMinQueryLength' must be an int32");
return false;
}
const int32_t val = bson_iter_int32(iter);
if (val <= 0) {
CLIENT_ERR(ERROR_PREFIX "'strMinQueryLength' must be greater than zero");
return false;
}
txio->strMinQueryLength = val;
}
END_IF_FIELD;
IF_FIELD(strMaxQueryLength);
{
if (!BSON_ITER_HOLDS_INT32(iter)) {
CLIENT_ERR(ERROR_PREFIX "'strMaxQueryLength' must be an int32");
return false;
}
const int32_t val = bson_iter_int32(iter);
if (val <= 0) {
CLIENT_ERR(ERROR_PREFIX "'strMaxQueryLength' must be greater than zero");
return false;
}
txio->strMaxQueryLength = val;
}
END_IF_FIELD;
CLIENT_ERR(ERROR_PREFIX "Unrecognized field: '%s'", field);
return false;
}
return true;
}
bool mc_TextOpts_parse(mc_TextOpts_t *txo, const bson_t *in, mongocrypt_status_t *status) {
bson_iter_t iter = {0};
BSON_ASSERT_PARAM(txo);
BSON_ASSERT_PARAM(in);
BSON_ASSERT(status || true);
bool has_caseSensitive = false, has_diacriticSensitive = false, has_substring = false, has_prefix = false,
has_suffix = false;
*txo = (mc_TextOpts_t){{0}};
if (!bson_iter_init(&iter, in)) {
CLIENT_ERR(ERROR_PREFIX "Invalid BSON");
return false;
}
while (bson_iter_next(&iter)) {
const char *field = bson_iter_key(&iter);
IF_FIELD(caseSensitive);
{
if (!BSON_ITER_HOLDS_BOOL(&iter)) {
CLIENT_ERR(ERROR_PREFIX "Expected bool for caseSensitive, got: %s",
mc_bson_type_to_string(bson_iter_type(&iter)));
return false;
}
txo->caseSensitive = bson_iter_bool(&iter);
}
END_IF_FIELD;
IF_FIELD(diacriticSensitive);
{
if (!BSON_ITER_HOLDS_BOOL(&iter)) {
CLIENT_ERR(ERROR_PREFIX "Expected bool for diacriticSensitive, got: %s",
mc_bson_type_to_string(bson_iter_type(&iter)));
return false;
}
txo->diacriticSensitive = bson_iter_bool(&iter);
}
END_IF_FIELD;
IF_FIELD(substring);
{
bson_iter_t subdoc;
if (!BSON_ITER_HOLDS_DOCUMENT(&iter) || !bson_iter_recurse(&iter, &subdoc)) {
CLIENT_ERR(ERROR_PREFIX "Expected document for substring, got: %s",
mc_bson_type_to_string(bson_iter_type(&iter)));
return false;
}
if (!mc_TextOptsPerIndex_parse(&txo->substring, &subdoc, status)) {
return false;
}
if (!txo->substring.strMaxLength.set) {
CLIENT_ERR(ERROR_PREFIX "'strMaxLength' must be set for substring");
return false;
}
}
END_IF_FIELD;
IF_FIELD(prefix);
{
bson_iter_t subdoc;
if (!BSON_ITER_HOLDS_DOCUMENT(&iter) || !bson_iter_recurse(&iter, &subdoc)) {
CLIENT_ERR(ERROR_PREFIX "Expected document for prefix, got: %s",
mc_bson_type_to_string(bson_iter_type(&iter)));
return false;
}
if (!mc_TextOptsPerIndex_parse(&txo->prefix, &subdoc, status)) {
return false;
}
if (txo->prefix.strMaxLength.set) {
CLIENT_ERR(ERROR_PREFIX "'strMaxLength' is not allowed in 'prefix'");
return false;
}
}
END_IF_FIELD;
IF_FIELD(suffix);
{
bson_iter_t subdoc;
if (!BSON_ITER_HOLDS_DOCUMENT(&iter) || !bson_iter_recurse(&iter, &subdoc)) {
CLIENT_ERR(ERROR_PREFIX "Expected document for suffix, got: %s",
mc_bson_type_to_string(bson_iter_type(&iter)));
return false;
}
if (!mc_TextOptsPerIndex_parse(&txo->suffix, &subdoc, status)) {
return false;
}
if (txo->suffix.strMaxLength.set) {
CLIENT_ERR(ERROR_PREFIX "'strMaxLength' is not allowed in 'suffix'");
return false;
}
}
END_IF_FIELD;
CLIENT_ERR(ERROR_PREFIX "Unrecognized field: '%s'", field);
return false;
}
if (!has_caseSensitive) {
CLIENT_ERR(ERROR_PREFIX "'caseSensitive' is required");
return false;
}
if (!has_diacriticSensitive) {
CLIENT_ERR(ERROR_PREFIX "'diacriticSensitive' is required");
return false;
}
if (has_substring && (has_prefix || has_suffix)) {
CLIENT_ERR(ERROR_PREFIX "Cannot specify 'substring' with 'prefix' or 'suffix'");
return false;
}
if (!(has_prefix || has_suffix || has_substring)) {
CLIENT_ERR(ERROR_PREFIX "One of 'prefix', 'suffix', or 'substring' is required");
return false;
}
return true;
}
#undef ERROR_PREFIX
#define ERROR_PREFIX "Error making FLE2RangeInsertSpec: "
static bool append_TextOptsPerIndex(const mc_TextOptsPerIndex_t *txio, bson_t *out, mongocrypt_status_t *status) {
if (txio->strMaxLength.set) {
if (!bson_append_int32(out, "mlen", -1, txio->strMaxLength.value)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
}
if (!bson_append_int32(out, "ub", -1, txio->strMaxQueryLength)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
if (!bson_append_int32(out, "lb", -1, txio->strMinQueryLength)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
return true;
}
bool mc_TextOpts_to_FLE2TextSearchInsertSpec(const mc_TextOpts_t *txo,
const bson_t *v,
bson_t *out,
mongocrypt_status_t *status) {
BSON_ASSERT_PARAM(txo);
BSON_ASSERT_PARAM(v);
BSON_ASSERT_PARAM(out);
BSON_ASSERT(status || true);
bson_iter_t v_iter;
if (!bson_iter_init_find(&v_iter, v, "v")) {
CLIENT_ERR(ERROR_PREFIX "Unable to find 'v' in input");
return false;
}
bson_t child;
if (!BSON_APPEND_DOCUMENT_BEGIN(out, "v", &child)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
if (!bson_append_iter(&child, "v", 1, &v_iter)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
if (!bson_append_bool(&child, "casef", -1, txo->caseSensitive)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
if (!bson_append_bool(&child, "diacf", -1, txo->diacriticSensitive)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
if (txo->prefix.set) {
bson_t insert_spec;
if (!BSON_APPEND_DOCUMENT_BEGIN(&child, "prefix", &insert_spec)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
if (!append_TextOptsPerIndex(&txo->prefix, &insert_spec, status)) {
return false;
}
if (!bson_append_document_end(&child, &insert_spec)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
}
if (txo->suffix.set) {
bson_t insert_spec;
if (!BSON_APPEND_DOCUMENT_BEGIN(&child, "suffix", &insert_spec)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
if (!append_TextOptsPerIndex(&txo->suffix, &insert_spec, status)) {
return false;
}
if (!bson_append_document_end(&child, &insert_spec)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
}
if (txo->substring.set) {
bson_t insert_spec;
if (!BSON_APPEND_DOCUMENT_BEGIN(&child, "substr", &insert_spec)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
if (!append_TextOptsPerIndex(&txo->substring, &insert_spec, status)) {
return false;
}
if (!bson_append_document_end(&child, &insert_spec)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
}
if (!bson_append_document_end(out, &child)) {
CLIENT_ERR(ERROR_PREFIX "Error appending to BSON");
return false;
}
return true;
}
#undef ERROR_PREFIX

View File

@ -1096,10 +1096,7 @@ static bool _fle2_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) {
BSON_ASSERT(context_uses_fle2(ctx));
BSON_ASSERT(ctx->state == MONGOCRYPT_CTX_READY);
if (ectx->explicit) {
return _mongocrypt_ctx_fail_w_msg(ctx, "explicit encryption is not yet supported. See MONGOCRYPT-409.");
}
BSON_ASSERT(!ectx->explicit);
if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &original_cmd_bson)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "malformed bson in original_cmd");
@ -1303,7 +1300,7 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
if (ctx->opts.rangeopts.set && ctx->opts.query_type.set) {
// RangeOpts with query type is a special case. The result contains two
// ciphertext values.
// ciphertext values of FLE2RangeFindSpec.
return FLE2RangeFindDriverSpec_to_ciphertexts(ctx, out);
}
@ -1317,6 +1314,9 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
_mongocrypt_ctx_fail_w_msg(ctx, "Cannot use rangePreview query type with Range V2");
goto fail;
// fallthrough
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW:
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW:
case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW:
case MONGOCRYPT_QUERY_TYPE_RANGE:
case MONGOCRYPT_QUERY_TYPE_EQUALITY: marking.u.fle2.type = MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND; break;
default: _mongocrypt_ctx_fail_w_msg(ctx, "Invalid value for EncryptOpts.queryType"); goto fail;
@ -1333,6 +1333,7 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
goto fail;
// fallthrough
case MONGOCRYPT_INDEX_TYPE_RANGE: marking.u.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_RANGE; break;
case MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW: marking.u.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_TEXT_SEARCH; break;
default:
// This might be unreachable because of other validation. Better safe than
// sorry.
@ -1342,8 +1343,7 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
if (ctx->opts.rangeopts.set) {
// Process the RangeOpts and the input 'v' document into a new 'v'.
// The new 'v' document will be a FLE2RangeFindSpec or
// FLE2RangeInsertSpec.
// The new 'v' document will be a FLE2RangeInsertSpec.
bson_t old_v;
if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &old_v)) {
@ -1365,6 +1365,22 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
marking.u.fle2.sparsity = ctx->opts.rangeopts.value.sparsity;
} else if (ctx->opts.textopts.set) {
bson_t old_v;
if (!_mongocrypt_buffer_to_bson(&ectx->original_cmd, &old_v)) {
_mongocrypt_ctx_fail_w_msg(ctx, "unable to convert input to BSON");
goto fail;
}
if (!mc_TextOpts_to_FLE2TextSearchInsertSpec(&ctx->opts.textopts.value, &old_v, &new_v, ctx->status)) {
_mongocrypt_ctx_fail(ctx);
goto fail;
}
if (!bson_iter_init_find(&marking.u.fle2.v_iter, &new_v, "v")) {
_mongocrypt_ctx_fail_w_msg(ctx, "invalid input BSON, must contain 'v'");
goto fail;
}
} else {
bson_t as_bson;
@ -1842,6 +1858,25 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set query type with no index type");
}
if (ctx->opts.query_type.set) {
const mongocrypt_query_type_t qt = ctx->opts.query_type.value;
if (qt == MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW) {
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "prefixPreview query type requires textPreview index type");
}
}
if (qt == MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW) {
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "suffixPreview query type requires textPreview index type");
}
}
if (qt == MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW) {
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "substringPreview query type requires textPreview index type");
}
}
}
if (ctx->opts.rangeopts.set && ctx->opts.index_type.set) {
if (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_NONE) {
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set range opts with no index type");
@ -1850,6 +1885,16 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
if (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_EQUALITY) {
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set range opts with equality index type");
}
if (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW) {
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set range opts with textPreview index type");
}
}
if (ctx->opts.textopts.set && ctx->opts.index_type.set) {
if (ctx->opts.index_type.value != MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW) {
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set text opts without textPreview index type");
}
}
if (ctx->opts.contention_factor.set && !mc_validate_contention(ctx->opts.contention_factor.value, ctx->status)) {
@ -1895,6 +1940,12 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
case MONGOCRYPT_QUERY_TYPE_EQUALITY:
matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_EQUALITY);
break;
// fallthrough
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW:
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW:
case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW:
matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW);
break;
default:
CLIENT_ERR("unsupported value for query_type: %d", (int)ctx->opts.query_type.value);
return _mongocrypt_ctx_fail(ctx);
@ -2172,7 +2223,8 @@ _check_cmd_for_auto_encrypt(mongocrypt_binary_t *cmd, bool *bypass, char **targe
eligible = true;
} else if (0 == strcmp(cmd_name, "hello")) {
*bypass = true;
} else if (0 == strcmp(cmd_name, "buildInfo")) {
} else if (0 == strcmp(cmd_name, "buildInfo") || 0 == strcmp(cmd_name, "buildinfo")) {
// Accept either case form to match server behavior.
*bypass = true;
} else if (0 == strcmp(cmd_name, "getCmdLineOpts")) {
*bypass = true;
@ -2186,6 +2238,8 @@ _check_cmd_for_auto_encrypt(mongocrypt_binary_t *cmd, bool *bypass, char **targe
*bypass = true;
} else if (0 == strcmp(cmd_name, "updateSearchIndex")) {
*bypass = true;
} else if (0 == strcmp(cmd_name, "serverStatus")) {
*bypass = true;
}
/* database/client commands are ineligible. */

View File

@ -21,6 +21,7 @@
#include "mc-optional-private.h"
#include "mc-rangeopts-private.h"
#include "mc-schema-broker-private.h"
#include "mc-textopts-private.h"
#include "mongocrypt-buffer-private.h"
#include "mongocrypt-endpoint-private.h"
#include "mongocrypt-key-broker-private.h"
@ -37,19 +38,15 @@ typedef enum {
_MONGOCRYPT_TYPE_COMPACT,
} _mongocrypt_ctx_type_t;
typedef enum {
MONGOCRYPT_INDEX_TYPE_NONE = 1,
MONGOCRYPT_INDEX_TYPE_EQUALITY = 2,
MONGOCRYPT_INDEX_TYPE_RANGE = 3,
MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED = 4
} mongocrypt_index_type_t;
const char *_mongocrypt_index_type_to_string(mongocrypt_index_type_t val);
typedef enum {
MONGOCRYPT_QUERY_TYPE_EQUALITY = 1,
MONGOCRYPT_QUERY_TYPE_RANGE = 2,
MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED = 3
MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED = 3,
MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW = 4,
MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW = 5,
MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW = 6,
} mongocrypt_query_type_t;
const char *_mongocrypt_query_type_to_string(mongocrypt_query_type_t val);
@ -87,6 +84,11 @@ typedef struct __mongocrypt_ctx_opts_t {
mc_RangeOpts_t value;
bool set;
} rangeopts;
struct {
mc_TextOpts_t value;
bool set;
} textopts;
} _mongocrypt_ctx_opts_t;
// `_mongocrypt_ctx_opts_t` inherits extended alignment from libbson. To dynamically allocate, use

View File

@ -16,8 +16,12 @@
#include <bson/bson.h>
#include "mc-textopts-private.h"
#include "mlib/str.h"
#include "mongocrypt-binary-private.h"
#include "mongocrypt-ctx-private.h"
#include "mongocrypt-key-broker-private.h"
#include "mongocrypt-private.h"
bool _mongocrypt_ctx_fail_w_msg(mongocrypt_ctx_t *ctx, const char *msg) {
BSON_ASSERT_PARAM(ctx);
@ -264,6 +268,9 @@ bool mongocrypt_ctx_setopt_algorithm(mongocrypt_ctx_t *ctx, const char *algorith
} else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_RANGEPREVIEW_DEPRECATED_STR))) {
_mongocrypt_ctx_fail_w_msg(ctx, "Algorithm 'rangePreview' is deprecated, please use 'range'");
return false;
} else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_TEXTPREVIEW_STR))) {
ctx->opts.index_type.value = MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW;
ctx->opts.index_type.set = true;
} else {
char *error = bson_strdup_printf("unsupported algorithm string \"%.*s\"",
algo_str.len <= (size_t)INT_MAX ? (int)algo_str.len : INT_MAX,
@ -1066,6 +1073,15 @@ bool mongocrypt_ctx_setopt_query_type(mongocrypt_ctx_t *ctx, const char *query_t
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED_STR))) {
_mongocrypt_ctx_fail_w_msg(ctx, "Query type 'rangePreview' is deprecated, please use 'range'");
return false;
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_STR))) {
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW;
ctx->opts.query_type.set = true;
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_STR))) {
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW;
ctx->opts.query_type.set = true;
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_STR))) {
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW;
ctx->opts.query_type.set = true;
} else {
/* don't check if qt_str.len fits in int; we want the diagnostic output */
char *error = bson_strdup_printf("Unsupported query_type \"%.*s\"",
@ -1084,6 +1100,7 @@ const char *_mongocrypt_index_type_to_string(mongocrypt_index_type_t val) {
case MONGOCRYPT_INDEX_TYPE_EQUALITY: return "Equality";
case MONGOCRYPT_INDEX_TYPE_RANGE: return "Range";
case MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED: return "RangePreview";
case MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW: return "TextPreview";
default: return "Unknown";
}
}
@ -1093,6 +1110,9 @@ const char *_mongocrypt_query_type_to_string(mongocrypt_query_type_t val) {
case MONGOCRYPT_QUERY_TYPE_EQUALITY: return "Equality";
case MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_DEPRECATED: return "RangePreview";
case MONGOCRYPT_QUERY_TYPE_RANGE: return "Range";
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW: return "PrefixPreview";
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW: return "SuffixPreview";
case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW: return "SubstringPreview";
default: return "Unknown";
}
}
@ -1127,3 +1147,32 @@ bool mongocrypt_ctx_setopt_algorithm_range(mongocrypt_ctx_t *ctx, mongocrypt_bin
ctx->opts.rangeopts.set = true;
return true;
}
bool mongocrypt_ctx_setopt_algorithm_text(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *opts) {
bson_t as_bson;
if (!ctx) {
return false;
}
if (ctx->initialized) {
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set options after init");
}
if (ctx->state == MONGOCRYPT_CTX_ERROR) {
return false;
}
if (ctx->opts.textopts.set) {
return _mongocrypt_ctx_fail_w_msg(ctx, "TextOpts already set");
}
if (!_mongocrypt_binary_to_bson(opts, &as_bson)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "invalid BSON");
}
if (!mc_TextOpts_parse(&ctx->opts.textopts.value, &as_bson, ctx->status)) {
return _mongocrypt_ctx_fail(ctx);
}
ctx->opts.textopts.set = true;
return true;
}

View File

@ -151,6 +151,14 @@ typedef enum {
MONGOCRYPT_FLE2_ALGORITHM_TEXT_SEARCH = 4
} mongocrypt_fle2_encryption_algorithm_t;
typedef enum {
MONGOCRYPT_INDEX_TYPE_NONE = 1,
MONGOCRYPT_INDEX_TYPE_EQUALITY = 2,
MONGOCRYPT_INDEX_TYPE_RANGE = 3,
MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED = 4,
MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW = 5,
} mongocrypt_index_type_t;
bool _mongocrypt_validate_and_copy_string(const char *in, int32_t in_len, char **out) MONGOCRYPT_WARN_UNUSED_RESULT;
char *_mongocrypt_new_string_from_bytes(const void *in, int len);

View File

@ -712,6 +712,8 @@ bool mongocrypt_ctx_setopt_algorithm(mongocrypt_ctx_t *ctx, const char *algorith
// DEPRECATED: support "RangePreview" has been removed in favor of "range".
#define MONGOCRYPT_ALGORITHM_RANGEPREVIEW_DEPRECATED_STR "RangePreview"
#define MONGOCRYPT_ALGORITHM_RANGE_STR "Range"
/// NOTE: "textPreview" is experimental only and may be removed in a future non-major release.
#define MONGOCRYPT_ALGORITHM_TEXTPREVIEW_STR "textPreview"
/**
* Identify the AWS KMS master key to use for creating a data key.
@ -1530,6 +1532,34 @@ bool mongocrypt_ctx_setopt_query_type(mongocrypt_ctx_t *ctx, const char *query_t
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_algorithm_range(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *opts);
/**
* Set options for explicit encryption with the "textPreview" algorithm.
*
* NOTE: "textPreview" is experimental only and may be removed in a future non-major release.
* @p opts is a BSON document of the form:
* {
* "caseSensitive": bool,
* . "diacriticSensitive": bool,
* . "prefix": Optional{
* . "strMaxQueryLength": Int32,
* . "strMinQueryLength": Int32,
* . },
* . "suffix": Optional{
* . "strMaxQueryLength": Int32,
* . "strMinQueryLength": Int32,
* . },
* . "substring": Optional{
* . "strMaxLength": Int32,
* . "strMaxQueryLength": Int32,
* . "strMinQueryLength": Int32,
* . },
* }
*
* "prefix" and "suffix" can both be set.
*/
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_algorithm_text(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *opts);
/**
* Set the expiration time for the data encryption key cache. Defaults to 60 seconds if not set.
*

View File

@ -18,8 +18,7 @@ if grep -q Microsoft /proc/version; then
fi
NAME=libmongocrypt
# TODO SERVER-106496 Update version number
VERSION=1.14.0
VERSION=1.15.0
if grep -q Microsoft /proc/version; then
SRC_ROOT=$(wslpath -u $(powershell.exe -Command "Get-ChildItem Env:TEMP | Get-Content | Write-Host"))
@ -44,9 +43,7 @@ if [ ! -d $SRC ]; then
$GIT_EXE clone https://github.com/mongodb/libmongocrypt $CLONE_DEST
pushd $SRC
# TODO: SERVER-106496 Revert back to `$VERSION` upon new release of libmongocrypt
# $GIT_EXE checkout $VERSION
$GIT_EXE checkout 0840a84aa78578b50ef586ebbb12e5318108db9b
$GIT_EXE checkout $VERSION
popd
fi