Skip to content

Commit 0110c05

Browse files
MONGOCRYPT-767 Increase tag count field size to 32 bits for text search types (#958)
* MONGOCRYPT-767 Increase tag count field size to 32 bits for text search types --------- Co-authored-by: Shreyas Kalyan <[email protected]>
1 parent 67f10bf commit 0110c05

File tree

5 files changed

+1027
-77
lines changed

5 files changed

+1027
-77
lines changed

src/mc-fle2-payload-iev-private-v2.h

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
*
7676
* Note that this format differs from FLE2IndexedEqualityEncryptedValueV2
7777
* in only two ways:
78-
* 1/ `edge_count` is introduced as an octet following `original_bson_type`.
78+
* 1/ `edge_count` is introduced as a 8 bit int following `original_bson_type`.
7979
* 2/ Rather than a single metadata block, we have {edge_count} blocks.
8080
*
8181
* FLE2IndexedTextEncryptedValue has the following data layout:
@@ -84,17 +84,18 @@
8484
* uint8_t fle_blob_subtype = 17;
8585
* uint8_t S_KeyId[16];
8686
* uint8_t original_bson_type;
87-
* uint8_t edge_count;
88-
* uint8_t substr_tag_count;
89-
* uint8_t suffix_tag_count;
87+
* uint32_t edge_count;
88+
* uint32_t substr_tag_count;
89+
* uint32_t suffix_tag_count;
9090
* uint8_t ServerEncryptedValue[ServerEncryptedValue.length];
9191
* FLE2TagAndEncryptedMetadataBlock exact_metadata;
9292
* FLE2TagAndEncryptedMetadataBlock substr_metadata[substr_tag_count];
9393
* FLE2TagAndEncryptedMetadataBlock suffix_metadata[suffix_tag_count];
9494
* FLE2TagAndEncryptedMetadataBlock prefix_metadata[edge_count - suffix_tag_count - substr_tag_count - 1];
9595
* }
9696
* The main difference in this format is that we split `metadata` into 4
97-
* sections, one for each text search index type. We add two octets,
97+
* sections, one for each text search index type. We expand edge_count
98+
* to be a 32 bit integer rather than 8 bit. We add two 32 bit ints,
9899
* `substr_tag_count` and `suffix_tag_count`, following `edge_count`
99100
* in order to track the delineation of the metadata. Similarly to
100101
* FLE2IndexedEqualityEncryptedValueV2, we have `edge_count` total
@@ -112,9 +113,9 @@ typedef struct _mc_FLE2IndexedEncryptedValueV2_t {
112113
// Raw payload values
113114
uint8_t fle_blob_subtype;
114115
uint8_t bson_value_type;
115-
uint8_t edge_count;
116-
uint8_t substr_tag_count;
117-
uint8_t suffix_tag_count;
116+
uint32_t edge_count;
117+
uint32_t substr_tag_count;
118+
uint32_t suffix_tag_count;
118119
_mongocrypt_buffer_t S_KeyId;
119120
_mongocrypt_buffer_t ServerEncryptedValue;
120121

@@ -151,8 +152,12 @@ bson_type_t mc_FLE2IndexedEncryptedValueV2_get_bson_value_type(const mc_FLE2Inde
151152
* original_bson_type (8u)
152153
* if (range)
153154
* edge_count(8u)
155+
* if (text)
156+
* edge_count(32u)
157+
* substr_tag_count(32u)
158+
* suffix_tag_count(32u)
154159
* ServerEncryptedValue (8u * SEV_len)
155-
* metadata (96u * {range ? edge_count : 1u})
160+
* metadata (96u * {range || text ? edge_count : 1u})
156161
*
157162
* Returns an error if the input buffer is not valid.
158163
*/
@@ -203,24 +208,24 @@ bool mc_FLE2IndexedEncryptedValueV2_add_K_Key(_mongocrypt_crypto_t *crypto,
203208
const _mongocrypt_buffer_t *mc_FLE2IndexedEncryptedValueV2_get_ClientValue(const mc_FLE2IndexedEncryptedValueV2_t *iev,
204209
mongocrypt_status_t *status);
205210

206-
uint8_t mc_FLE2IndexedEncryptedValueV2_get_edge_count(const mc_FLE2IndexedEncryptedValueV2_t *iev,
207-
mongocrypt_status_t *status);
211+
uint32_t mc_FLE2IndexedEncryptedValueV2_get_edge_count(const mc_FLE2IndexedEncryptedValueV2_t *iev,
212+
mongocrypt_status_t *status);
208213

209214
bool mc_FLE2IndexedEncryptedValueV2_get_substr_tag_count(const mc_FLE2IndexedEncryptedValueV2_t *iev,
210-
uint8_t *count,
215+
uint32_t *count,
211216
mongocrypt_status_t *status);
212217

213218
bool mc_FLE2IndexedEncryptedValueV2_get_suffix_tag_count(const mc_FLE2IndexedEncryptedValueV2_t *iev,
214-
uint8_t *count,
219+
uint32_t *count,
215220
mongocrypt_status_t *status);
216221

217222
bool mc_FLE2IndexedEncryptedValueV2_get_prefix_tag_count(const mc_FLE2IndexedEncryptedValueV2_t *iev,
218-
uint8_t *count,
223+
uint32_t *count,
219224
mongocrypt_status_t *status);
220225

221226
bool mc_FLE2IndexedEncryptedValueV2_get_edge(const mc_FLE2IndexedEncryptedValueV2_t *iev,
222227
mc_FLE2TagAndEncryptedMetadataBlock_t *out,
223-
const uint8_t edge_index,
228+
const uint32_t edge_index,
224229
mongocrypt_status_t *status);
225230

226231
bool mc_FLE2IndexedEncryptedValueV2_get_metadata(const mc_FLE2IndexedEncryptedValueV2_t *iev,
@@ -233,17 +238,17 @@ bool mc_FLE2IndexedEncryptedValueV2_get_exact_metadata(const mc_FLE2IndexedEncry
233238

234239
bool mc_FLE2IndexedEncryptedValueV2_get_substr_metadata(const mc_FLE2IndexedEncryptedValueV2_t *iev,
235240
mc_FLE2TagAndEncryptedMetadataBlock_t *out,
236-
const uint8_t block_index,
241+
const uint32_t block_index,
237242
mongocrypt_status_t *status);
238243

239244
bool mc_FLE2IndexedEncryptedValueV2_get_suffix_metadata(const mc_FLE2IndexedEncryptedValueV2_t *iev,
240245
mc_FLE2TagAndEncryptedMetadataBlock_t *out,
241-
const uint8_t block_index,
246+
const uint32_t block_index,
242247
mongocrypt_status_t *status);
243248

244249
bool mc_FLE2IndexedEncryptedValueV2_get_prefix_metadata(const mc_FLE2IndexedEncryptedValueV2_t *iev,
245250
mc_FLE2TagAndEncryptedMetadataBlock_t *out,
246-
const uint8_t block_index,
251+
const uint32_t block_index,
247252
mongocrypt_status_t *status);
248253

249254
void mc_FLE2IndexedEncryptedValueV2_destroy(mc_FLE2IndexedEncryptedValueV2_t *iev);

src/mc-fle2-payload-iev-v2.c

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ void mc_FLE2IndexedEncryptedValueV2_destroy(mc_FLE2IndexedEncryptedValueV2_t *ie
267267
_mongocrypt_buffer_cleanup(&iev->ServerEncryptedValue);
268268
_mongocrypt_buffer_cleanup(&iev->S_KeyId);
269269

270-
for (int i = 0; i < iev->edge_count; i++) {
270+
for (uint32_t i = 0; i < iev->edge_count; i++) {
271271
mc_FLE2TagAndEncryptedMetadataBlock_cleanup(&iev->metadata[i]);
272272
}
273273

@@ -277,8 +277,8 @@ void mc_FLE2IndexedEncryptedValueV2_destroy(mc_FLE2IndexedEncryptedValueV2_t *ie
277277
bson_free(iev);
278278
}
279279

280-
uint8_t mc_FLE2IndexedEncryptedValueV2_get_edge_count(const mc_FLE2IndexedEncryptedValueV2_t *iev,
281-
mongocrypt_status_t *status) {
280+
uint32_t mc_FLE2IndexedEncryptedValueV2_get_edge_count(const mc_FLE2IndexedEncryptedValueV2_t *iev,
281+
mongocrypt_status_t *status) {
282282
BSON_ASSERT_PARAM(iev);
283283

284284
if (iev->type == kFLE2IEVTypeInitV2) {
@@ -297,7 +297,7 @@ uint8_t mc_FLE2IndexedEncryptedValueV2_get_edge_count(const mc_FLE2IndexedEncryp
297297
}
298298

299299
bool mc_FLE2IndexedEncryptedValueV2_get_substr_tag_count(const mc_FLE2IndexedEncryptedValueV2_t *iev,
300-
uint8_t *count,
300+
uint32_t *count,
301301
mongocrypt_status_t *status) {
302302
BSON_ASSERT_PARAM(iev);
303303
BSON_ASSERT_PARAM(count);
@@ -319,7 +319,7 @@ bool mc_FLE2IndexedEncryptedValueV2_get_substr_tag_count(const mc_FLE2IndexedEnc
319319
}
320320

321321
bool mc_FLE2IndexedEncryptedValueV2_get_suffix_tag_count(const mc_FLE2IndexedEncryptedValueV2_t *iev,
322-
uint8_t *count,
322+
uint32_t *count,
323323
mongocrypt_status_t *status) {
324324
BSON_ASSERT_PARAM(iev);
325325
BSON_ASSERT_PARAM(count);
@@ -341,7 +341,7 @@ bool mc_FLE2IndexedEncryptedValueV2_get_suffix_tag_count(const mc_FLE2IndexedEnc
341341
}
342342

343343
bool mc_FLE2IndexedEncryptedValueV2_get_prefix_tag_count(const mc_FLE2IndexedEncryptedValueV2_t *iev,
344-
uint8_t *count,
344+
uint32_t *count,
345345
mongocrypt_status_t *status) {
346346
BSON_ASSERT_PARAM(iev);
347347
BSON_ASSERT_PARAM(count);
@@ -358,13 +358,13 @@ bool mc_FLE2IndexedEncryptedValueV2_get_prefix_tag_count(const mc_FLE2IndexedEnc
358358
return false;
359359
}
360360

361-
*count = (uint8_t)(iev->edge_count - iev->substr_tag_count - iev->suffix_tag_count - 1);
361+
*count = (uint32_t)(iev->edge_count - iev->substr_tag_count - iev->suffix_tag_count - 1);
362362
return true;
363363
}
364364

365365
bool mc_FLE2IndexedEncryptedValueV2_get_edge(const mc_FLE2IndexedEncryptedValueV2_t *iev,
366366
mc_FLE2TagAndEncryptedMetadataBlock_t *out,
367-
const uint8_t edge_index,
367+
const uint32_t edge_index,
368368
mongocrypt_status_t *status) {
369369
BSON_ASSERT_PARAM(iev);
370370
BSON_ASSERT_PARAM(out);
@@ -376,7 +376,7 @@ bool mc_FLE2IndexedEncryptedValueV2_get_edge(const mc_FLE2IndexedEncryptedValueV
376376
return false;
377377
}
378378

379-
if (iev->type != kFLE2IEVTypeRangeV2) {
379+
if (iev->type != kFLE2IEVTypeRangeV2 && iev->type != kFLE2IEVTypeText) {
380380
CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_get_edge must be called with type range");
381381
return false;
382382
}
@@ -440,7 +440,7 @@ bool mc_FLE2IndexedEncryptedValueV2_get_exact_metadata(const mc_FLE2IndexedEncry
440440

441441
bool mc_FLE2IndexedEncryptedValueV2_get_substr_metadata(const mc_FLE2IndexedEncryptedValueV2_t *iev,
442442
mc_FLE2TagAndEncryptedMetadataBlock_t *out,
443-
const uint8_t block_index,
443+
const uint32_t block_index,
444444
mongocrypt_status_t *status) {
445445
BSON_ASSERT_PARAM(iev);
446446
BSON_ASSERT_PARAM(out);
@@ -470,7 +470,7 @@ bool mc_FLE2IndexedEncryptedValueV2_get_substr_metadata(const mc_FLE2IndexedEncr
470470

471471
bool mc_FLE2IndexedEncryptedValueV2_get_suffix_metadata(const mc_FLE2IndexedEncryptedValueV2_t *iev,
472472
mc_FLE2TagAndEncryptedMetadataBlock_t *out,
473-
const uint8_t block_index,
473+
const uint32_t block_index,
474474
mongocrypt_status_t *status) {
475475
BSON_ASSERT_PARAM(iev);
476476
BSON_ASSERT_PARAM(out);
@@ -500,13 +500,13 @@ bool mc_FLE2IndexedEncryptedValueV2_get_suffix_metadata(const mc_FLE2IndexedEncr
500500

501501
bool mc_FLE2IndexedEncryptedValueV2_get_prefix_metadata(const mc_FLE2IndexedEncryptedValueV2_t *iev,
502502
mc_FLE2TagAndEncryptedMetadataBlock_t *out,
503-
const uint8_t block_index,
503+
const uint32_t block_index,
504504
mongocrypt_status_t *status) {
505505
BSON_ASSERT_PARAM(iev);
506506
BSON_ASSERT_PARAM(out);
507507

508508
// We can skip the check for text type because get_prefix_tag_count does it for us.
509-
uint8_t prefix_tag_count;
509+
uint32_t prefix_tag_count;
510510
if (!mc_FLE2IndexedEncryptedValueV2_get_prefix_tag_count(iev, &prefix_tag_count, status)) {
511511
return false;
512512
}
@@ -571,14 +571,23 @@ bool mc_FLE2IndexedEncryptedValueV2_parse(mc_FLE2IndexedEncryptedValueV2_t *iev,
571571
if (iev->type == kFLE2IEVTypeEqualityV2) {
572572
iev->edge_count = 1;
573573
} else {
574-
CHECK_AND_RETURN(mc_reader_read_u8(&reader, &iev->edge_count, status));
575-
if (iev->type == kFLE2IEVTypeText) {
576-
CHECK_AND_RETURN(mc_reader_read_u8(&reader, &iev->substr_tag_count, status));
577-
CHECK_AND_RETURN(mc_reader_read_u8(&reader, &iev->suffix_tag_count, status));
574+
if (iev->type == kFLE2IEVTypeRangeV2) {
575+
uint8_t ec;
576+
CHECK_AND_RETURN(mc_reader_read_u8(&reader, &ec, status));
577+
if (ec == 0) {
578+
CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_parse edge count must not be 0 for type "
579+
"range, but found edge count is 0.");
580+
return false;
581+
}
582+
iev->edge_count = (uint32_t)ec;
583+
} else if (iev->type == kFLE2IEVTypeText) {
584+
CHECK_AND_RETURN(mc_reader_read_u32(&reader, &iev->edge_count, status));
585+
CHECK_AND_RETURN(mc_reader_read_u32(&reader, &iev->substr_tag_count, status));
586+
CHECK_AND_RETURN(mc_reader_read_u32(&reader, &iev->suffix_tag_count, status));
578587
// Upconvert so that addition doesn't overflow
579-
if ((uint16_t)iev->edge_count < (uint16_t)iev->substr_tag_count + (uint16_t)iev->suffix_tag_count + 1) {
588+
if ((uint64_t)iev->edge_count < (uint64_t)iev->substr_tag_count + (uint64_t)iev->suffix_tag_count + 1) {
580589
CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_parse for text type expected edge count to be "
581-
"at least substr_tag_count + suffix_count + 1, but: %" PRIu8 " < %" PRIu8 " + %" PRIu8
590+
"at least substr_tag_count + suffix_count + 1, but: %" PRIu32 " < %" PRIu32 " + %" PRIu32
582591
" + 1",
583592
iev->edge_count,
584593
iev->substr_tag_count,
@@ -588,7 +597,7 @@ bool mc_FLE2IndexedEncryptedValueV2_parse(mc_FLE2IndexedEncryptedValueV2_t *iev,
588597
}
589598
}
590599

591-
// Maximum edge_count(255) times kMetadataLen(96) fits easily without
600+
// Maximum edge_count(4294967295) times kMetadataLen(96) fits easily without
592601
// overflow.
593602
const uint64_t metadata_len = iev->edge_count * kMetadataLen;
594603

@@ -607,8 +616,8 @@ bool mc_FLE2IndexedEncryptedValueV2_parse(mc_FLE2IndexedEncryptedValueV2_t *iev,
607616
iev->metadata = (mc_FLE2TagAndEncryptedMetadataBlock_t *)bson_malloc0(
608617
iev->edge_count * sizeof(mc_FLE2TagAndEncryptedMetadataBlock_t));
609618

610-
// Read each metadata element
611-
for (uint8_t i = 0; i < iev->edge_count; i++) {
619+
// Read each metadata element in buff
620+
for (uint32_t i = 0; i < iev->edge_count; i++) {
612621
_mongocrypt_buffer_t tmp_buf;
613622

614623
CHECK_AND_RETURN(mc_reader_read_buffer(&reader, &tmp_buf, kMetadataLen, status));
@@ -624,13 +633,12 @@ static inline uint32_t mc_FLE2IndexedEncryptedValueV2_serialized_length(const mc
624633
// fle_blob_subtype: 1 byte
625634
// S_KeyId: UUID_LEN bytes
626635
// bson_value_type: 1 byte
627-
// if range or text: edge_count: 1 byte
628-
// if text: tag counts: 2 bytes
636+
// if range: edge_count: 1 byte
637+
// if text: edge + tag counts: 12 bytes
629638
// ServerEncryptedValue: ServerEncryptedValue.len bytes
630639
// metadata: edge_count * kMetadataLen bytes
631-
return iev->ServerEncryptedValue.len + 1 + UUID_LEN + 1
632-
+ (iev->type == kFLE2IEVTypeRangeV2 || iev->type == kFLE2IEVTypeText ? 1 : 0)
633-
+ (iev->type == kFLE2IEVTypeText ? 2 : 0) + iev->edge_count * kMetadataLen;
640+
return iev->ServerEncryptedValue.len + 1 + UUID_LEN + 1 + (iev->type == kFLE2IEVTypeRangeV2 ? 1 : 0)
641+
+ (iev->type == kFLE2IEVTypeText ? 12 : 0) + iev->edge_count * kMetadataLen;
634642
}
635643

636644
bool mc_FLE2IndexedEncryptedValueV2_serialize(const mc_FLE2IndexedEncryptedValueV2_t *iev,
@@ -658,22 +666,22 @@ bool mc_FLE2IndexedEncryptedValueV2_serialize(const mc_FLE2IndexedEncryptedValue
658666
// Serialize bson_value_type
659667
CHECK_AND_RETURN(mc_writer_write_u8(&writer, iev->bson_value_type, status));
660668

661-
if (iev->type == kFLE2IEVTypeRangeV2 || iev->type == kFLE2IEVTypeText) {
669+
if (iev->type == kFLE2IEVTypeRangeV2) {
662670
// Serialize edge_count (only serialized for types range and text)
663-
CHECK_AND_RETURN(mc_writer_write_u8(&writer, iev->edge_count, status));
664-
if (iev->type == kFLE2IEVTypeText) {
665-
// Serialize substr/suffix_tag_count (only serialized for text)
666-
CHECK_AND_RETURN(mc_writer_write_u8(&writer, iev->substr_tag_count, status));
667-
CHECK_AND_RETURN(mc_writer_write_u8(&writer, iev->suffix_tag_count, status));
668-
}
671+
CHECK_AND_RETURN(mc_writer_write_u8(&writer, (uint8_t)iev->edge_count, status));
672+
} else if (iev->type == kFLE2IEVTypeText) {
673+
// Serialize substr/suffix_tag_count (only serialized for text)
674+
CHECK_AND_RETURN(mc_writer_write_u32(&writer, iev->edge_count, status));
675+
CHECK_AND_RETURN(mc_writer_write_u32(&writer, iev->substr_tag_count, status));
676+
CHECK_AND_RETURN(mc_writer_write_u32(&writer, iev->suffix_tag_count, status));
669677
}
670678

671679
// Serialize encrypted value
672680
CHECK_AND_RETURN(
673681
mc_writer_write_buffer(&writer, &iev->ServerEncryptedValue, iev->ServerEncryptedValue.len, status));
674682

675683
// Serialize metadata
676-
for (int i = 0; i < iev->edge_count; ++i) {
684+
for (uint32_t i = 0; i < iev->edge_count; ++i) {
677685
_mongocrypt_buffer_t tmp_buf;
678686
_mongocrypt_buffer_init(&tmp_buf);
679687

@@ -744,13 +752,18 @@ static bool validate_for_equality(const mc_FLE2IndexedEncryptedValueV2_t *iev, m
744752
static bool validate_for_range(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status) {
745753
CHECK(iev->fle_blob_subtype == MC_SUBTYPE_FLE2IndexedRangeEncryptedValueV2, "fle_blob_subtype does not match type");
746754
CHECK(is_fle2_range_indexed_supported_type(iev->bson_value_type), "bson_value_type is invalid");
755+
if (iev->edge_count > (uint32_t)UINT8_MAX) {
756+
CLIENT_ERR("mc_FLE2IndexedEncryptedValueV2_validate failed: edge count for range encrypted value "
757+
"must be less than max uint8_t. Got: %" PRIu32,
758+
iev->edge_count);
759+
}
747760
return true;
748761
}
749762

750763
static bool validate_for_text(const mc_FLE2IndexedEncryptedValueV2_t *iev, mongocrypt_status_t *status) {
751764
CHECK(iev->fle_blob_subtype == MC_SUBTYPE_FLE2IndexedTextEncryptedValue, "fle_blob_subtype does not match type");
752765
CHECK(is_fle2_text_indexed_supported_type(iev->bson_value_type), "bson_value_type is invalid");
753-
CHECK((uint16_t)iev->edge_count >= (uint16_t)iev->substr_tag_count + (uint16_t)iev->suffix_tag_count + 1,
766+
CHECK((uint64_t)iev->edge_count >= (uint64_t)iev->substr_tag_count + (uint64_t)iev->suffix_tag_count + 1,
754767
"edge_count is smaller than substr_tag_count + suffix_tag_count + 1");
755768
return true;
756769
}
@@ -798,7 +811,7 @@ bool mc_FLE2IndexedEncryptedValueV2_validate(const mc_FLE2IndexedEncryptedValueV
798811
CHECK(iev->ClientValue.len == ClientValueLen, "ClientValue.len was unexpected");
799812
}
800813
CHECK(iev->edge_count > 0, "edge_count must be at least 1");
801-
for (uint8_t i = 0; i < iev->edge_count; i++) {
814+
for (uint32_t i = 0; i < iev->edge_count; i++) {
802815
if (!mc_FLE2TagAndEncryptedMetadataBlock_validate(&iev->metadata[i], status)) {
803816
return false;
804817
}

0 commit comments

Comments
 (0)