2020
2121#include "mc-fle2-encryption-placeholder-private.h"
2222#include "mongocrypt-buffer-private.h"
23+ #include "mongocrypt-private.h"
24+ #include "mongocrypt-util-private.h" // mc_bson_type_to_string
2325#include "mongocrypt.h"
2426
2527#define CLIENT_ERR_PREFIXED_HELPER (Prefix , ErrorString , ...) CLIENT_ERR(Prefix ": " ErrorString, ##__VA_ARGS__)
4446 goto fail; \
4547 }
4648
49+ // Common logic for parsing int32 greater than zero
50+ #define IF_FIELD_INT32_GT0_PARSE (Name , Dest , Iter ) \
51+ IF_FIELD(Name) { \
52+ if (!BSON_ITER_HOLDS_INT32(&Iter)) { \
53+ CLIENT_ERR_PREFIXED("'" #Name "' must be an int32"); \
54+ goto fail; \
55+ } \
56+ int32_t val = bson_iter_int32(&Iter); \
57+ if (val <= 0) { \
58+ CLIENT_ERR_PREFIXED("'" #Name "' must be greater than zero"); \
59+ goto fail; \
60+ } \
61+ Dest = (uint32_t)val; \
62+ } \
63+ END_IF_FIELD
64+
4765void mc_FLE2EncryptionPlaceholder_init (mc_FLE2EncryptionPlaceholder_t * placeholder ) {
4866 memset (placeholder , 0 , sizeof (mc_FLE2EncryptionPlaceholder_t ));
4967}
@@ -94,7 +112,7 @@ bool mc_FLE2EncryptionPlaceholder_parse(mc_FLE2EncryptionPlaceholder_t *out,
94112 }
95113 algorithm = bson_iter_int32 (& iter );
96114 if (algorithm != MONGOCRYPT_FLE2_ALGORITHM_UNINDEXED && algorithm != MONGOCRYPT_FLE2_ALGORITHM_EQUALITY
97- && algorithm != MONGOCRYPT_FLE2_ALGORITHM_RANGE ) {
115+ && algorithm != MONGOCRYPT_FLE2_ALGORITHM_RANGE && algorithm != MONGOCRYPT_FLE2_ALGORITHM_TEXT_SEARCH ) {
98116 CLIENT_ERR_PREFIXED ("invalid algorithm value: %d" , algorithm );
99117 goto fail ;
100118 }
@@ -491,3 +509,210 @@ bool mc_FLE2RangeInsertSpec_parse(mc_FLE2RangeInsertSpec_t *out,
491509}
492510
493511#undef ERROR_PREFIX
512+
513+ #define ERROR_PREFIX "Error parsing FLE2SubstringInsertSpec"
514+
515+ static bool mc_FLE2SubstringInsertSpec_parse (mc_FLE2SubstringInsertSpec_t * out ,
516+ const bson_iter_t * in ,
517+ mongocrypt_status_t * status ) {
518+ bson_iter_t iter ;
519+ bool has_mlen = false, has_ub = false, has_lb = false;
520+ BSON_ASSERT_PARAM (out );
521+ BSON_ASSERT_PARAM (in );
522+
523+ iter = * in ;
524+
525+ if (!BSON_ITER_HOLDS_DOCUMENT (& iter )) {
526+ CLIENT_ERR_PREFIXED ("must be an iterator to a document" );
527+ return false;
528+ }
529+ bson_iter_recurse (& iter , & iter );
530+ while (bson_iter_next (& iter )) {
531+ const char * field = bson_iter_key (& iter );
532+ BSON_ASSERT (field );
533+ IF_FIELD_INT32_GT0_PARSE (mlen , out -> mlen , iter );
534+ IF_FIELD_INT32_GT0_PARSE (ub , out -> ub , iter );
535+ IF_FIELD_INT32_GT0_PARSE (lb , out -> lb , iter );
536+ }
537+ CHECK_HAS (mlen )
538+ CHECK_HAS (ub )
539+ CHECK_HAS (lb )
540+ if (out - > ub < out - > lb ) {
541+ CLIENT_ERR_PREFIXED ("upper bound cannot be less than the lower bound" );
542+ goto fail ;
543+ }
544+ if (out -> mlen < out -> ub ) {
545+ CLIENT_ERR_PREFIXED ("maximum indexed length cannot be less than the upper bound" );
546+ goto fail ;
547+ }
548+ return true;
549+ fail :
550+ return false;
551+ }
552+
553+ #undef ERROR_PREFIX
554+
555+ #define ERROR_PREFIX "Error parsing FLE2SuffixInsertSpec"
556+
557+ static bool
558+ mc_FLE2SuffixInsertSpec_parse (mc_FLE2SuffixInsertSpec_t * out , const bson_iter_t * in , mongocrypt_status_t * status ) {
559+ bson_iter_t iter ;
560+ bool has_ub = false, has_lb = false;
561+
562+ BSON_ASSERT_PARAM (out );
563+ BSON_ASSERT_PARAM (in );
564+
565+ iter = * in ;
566+
567+ if (!BSON_ITER_HOLDS_DOCUMENT (& iter )) {
568+ CLIENT_ERR_PREFIXED ("must be an iterator to a document" );
569+ return false;
570+ }
571+ bson_iter_recurse (& iter , & iter );
572+ while (bson_iter_next (& iter )) {
573+ const char * field = bson_iter_key (& iter );
574+ BSON_ASSERT (field );
575+ IF_FIELD_INT32_GT0_PARSE (ub , out -> ub , iter );
576+ IF_FIELD_INT32_GT0_PARSE (lb , out -> lb , iter );
577+ }
578+ CHECK_HAS (ub )
579+ CHECK_HAS (lb )
580+ if (out - > ub < out - > lb ) {
581+ CLIENT_ERR_PREFIXED ("upper bound cannot be less than the lower bound" );
582+ goto fail ;
583+ }
584+ return true;
585+ fail :
586+ return false;
587+ }
588+
589+ #undef ERROR_PREFIX
590+
591+ #define ERROR_PREFIX "Error parsing FLE2PrefixInsertSpec"
592+
593+ static bool
594+ mc_FLE2PrefixInsertSpec_parse (mc_FLE2PrefixInsertSpec_t * out , const bson_iter_t * in , mongocrypt_status_t * status ) {
595+ bson_iter_t iter ;
596+ bool has_ub = false, has_lb = false;
597+ BSON_ASSERT_PARAM (out );
598+ BSON_ASSERT_PARAM (in );
599+
600+ iter = * in ;
601+
602+ if (!BSON_ITER_HOLDS_DOCUMENT (& iter )) {
603+ CLIENT_ERR_PREFIXED ("must be an iterator to a document" );
604+ return false;
605+ }
606+ bson_iter_recurse (& iter , & iter );
607+ while (bson_iter_next (& iter )) {
608+ const char * field = bson_iter_key (& iter );
609+ BSON_ASSERT (field );
610+ IF_FIELD_INT32_GT0_PARSE (ub , out -> ub , iter );
611+ IF_FIELD_INT32_GT0_PARSE (lb , out -> lb , iter );
612+ }
613+ CHECK_HAS (ub )
614+ CHECK_HAS (lb )
615+ if (out - > ub < out - > lb ) {
616+ CLIENT_ERR_PREFIXED ("upper bound cannot be less than the lower bound" );
617+ goto fail ;
618+ }
619+ return true;
620+ fail :
621+ return false;
622+ }
623+
624+ #undef ERROR_PREFIX
625+
626+ #define ERROR_PREFIX "Error parsing FLE2TextSearchInsertSpec"
627+
628+ bool mc_FLE2TextSearchInsertSpec_parse (mc_FLE2TextSearchInsertSpec_t * out ,
629+ const bson_iter_t * in ,
630+ mongocrypt_status_t * status ) {
631+ BSON_ASSERT_PARAM (out );
632+ BSON_ASSERT_PARAM (in );
633+
634+ * out = (mc_FLE2TextSearchInsertSpec_t ){{0 }};
635+
636+ bson_iter_t iter = * in ;
637+ bool has_v = false, has_casef = false, has_diacf = false;
638+ bool has_substr = false, has_suffix = false, has_prefix = false;
639+
640+ if (!BSON_ITER_HOLDS_DOCUMENT (& iter )) {
641+ CLIENT_ERR_PREFIXED ("must be an iterator to a document" );
642+ return false;
643+ }
644+ bson_iter_recurse (& iter , & iter );
645+
646+ while (bson_iter_next (& iter )) {
647+ const char * field = bson_iter_key (& iter );
648+ BSON_ASSERT (field );
649+
650+ IF_FIELD (v ) {
651+ out -> v = bson_iter_utf8 (& iter , & out -> len );
652+ if (!out -> v ) {
653+ CLIENT_ERR_PREFIXED ("unsupported BSON type: %s for text search" ,
654+ mc_bson_type_to_string (bson_iter_type (& iter )));
655+ goto fail ;
656+ }
657+ out -> v_iter = iter ;
658+ }
659+ END_IF_FIELD
660+
661+ IF_FIELD (casef ) {
662+ if (!BSON_ITER_HOLDS_BOOL (& iter )) {
663+ CLIENT_ERR_PREFIXED ("'casef' must be a bool" );
664+ goto fail ;
665+ }
666+ out -> casef = bson_iter_bool (& iter );
667+ }
668+ END_IF_FIELD
669+
670+ IF_FIELD (diacf ) {
671+ if (!BSON_ITER_HOLDS_BOOL (& iter )) {
672+ CLIENT_ERR_PREFIXED ("'diacf' must be a bool" );
673+ goto fail ;
674+ }
675+ out -> diacf = bson_iter_bool (& iter );
676+ }
677+ END_IF_FIELD
678+
679+ IF_FIELD (substr ) {
680+ if (!mc_FLE2SubstringInsertSpec_parse (& out -> substr .value , & iter , status )) {
681+ goto fail ;
682+ }
683+ out -> substr .set = true;
684+ }
685+ END_IF_FIELD
686+
687+ IF_FIELD (suffix ) {
688+ if (!mc_FLE2SuffixInsertSpec_parse (& out -> suffix .value , & iter , status )) {
689+ goto fail ;
690+ }
691+ out -> suffix .set = true;
692+ }
693+ END_IF_FIELD
694+
695+ IF_FIELD (prefix ) {
696+ if (!mc_FLE2PrefixInsertSpec_parse (& out -> prefix .value , & iter , status )) {
697+ goto fail ;
698+ }
699+ out -> prefix .set = true;
700+ }
701+ END_IF_FIELD
702+ }
703+
704+ CHECK_HAS (v )
705+ CHECK_HAS (casef )
706+ CHECK_HAS (diacf )
707+ // one of substr/suffix/prefix must be set
708+ if (!(has_substr || has_suffix || has_prefix )) {
709+ CLIENT_ERR_PREFIXED ("Must have a substring, suffix, or prefix index specification" );
710+ goto fail ;
711+ }
712+ return true;
713+
714+ fail :
715+ return false;
716+ }
717+
718+ #undef ERROR_PREFIX
0 commit comments