/* * Copyright 2019-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 #include "test-mongocrypt-assert-match-bson.h" #include "test-mongocrypt.h" #include "test-mongocrypt-crypto-std-hooks.h" static void _test_explicit_encrypt_init (_mongocrypt_tester_t *tester) { mongocrypt_binary_t *string_msg; mongocrypt_binary_t *no_v_msg; mongocrypt_binary_t *bad_name; mongocrypt_binary_t *name; mongocrypt_binary_t *msg; mongocrypt_binary_t *key_id; mongocrypt_binary_t *tmp; mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; bson_t *bson_msg; bson_t *bson_msg_no_v; bson_t *bson_name; bson_t *bson_bad_name; char *random = MONGOCRYPT_ALGORITHM_RANDOM_STR; char *deterministic = MONGOCRYPT_ALGORITHM_DETERMINISTIC_STR; bson_msg = BCON_NEW ("v", "hello"); msg = mongocrypt_binary_new_from_data ((uint8_t *) bson_get_data (bson_msg), bson_msg->len); bson_msg_no_v = BCON_NEW ("a", "hello"); no_v_msg = mongocrypt_binary_new_from_data ( (uint8_t *) bson_get_data (bson_msg_no_v), bson_msg_no_v->len); bson_name = BCON_NEW ("keyAltName", "Rebekah"); name = mongocrypt_binary_new_from_data ( (uint8_t *) bson_get_data (bson_name), bson_name->len); bson_bad_name = BCON_NEW ("noAltName", "Barry"); bad_name = mongocrypt_binary_new_from_data ( (uint8_t *) bson_get_data (bson_bad_name), bson_bad_name->len); string_msg = mongocrypt_binary_new_from_data (MONGOCRYPT_DATA_AND_LEN ("hello")); key_id = mongocrypt_binary_new_from_data ( MONGOCRYPT_DATA_AND_LEN ("2395340598345034")); crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); /* Initting with no options will fail (need key_id). */ ctx = mongocrypt_ctx_new (crypt); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, msg), ctx, "either key id or key alt name required"); mongocrypt_ctx_destroy (ctx); /* Initting with only key_id will not succeed, we also need an algorithm. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, msg), ctx, "algorithm or index type required"); mongocrypt_ctx_destroy (ctx); /* Test null msg input. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, NULL), ctx, "msg required for explicit encryption"); mongocrypt_ctx_destroy (ctx); /* Test with string msg input (no bson) */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, string_msg), ctx, "msg must be bson"); mongocrypt_ctx_destroy (ctx); /* Test with input bson that has no "v" field */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, no_v_msg), ctx, "invalid msg, must contain 'v'"); mongocrypt_ctx_destroy (ctx); /* Initting with RANDOM passes */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init (ctx, msg), ctx); BSON_ASSERT (ctx->opts.algorithm == MONGOCRYPT_ENCRYPTION_ALGORITHM_RANDOM); mongocrypt_ctx_destroy (ctx); /* Test that bad algorithm input fails */ ctx = mongocrypt_ctx_new (crypt); ASSERT_FAILS ( mongocrypt_ctx_setopt_algorithm (ctx, "nonexistent algorithm", -1), ctx, "unsupported algorithm"); mongocrypt_ctx_destroy (ctx); /* Test with badly formatted key alt name */ ctx = mongocrypt_ctx_new (crypt); ASSERT_FAILS (mongocrypt_ctx_setopt_key_alt_name (ctx, bad_name), ctx, "must have field"); mongocrypt_ctx_destroy (ctx); /* Test with key alt name */ ctx = mongocrypt_ctx_new (crypt); BSON_ASSERT (mongocrypt_ctx_setopt_key_alt_name (ctx, name)); BSON_ASSERT (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1)); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init (ctx, msg), ctx); /* After initing, we should be at NEED_KEYS */ BSON_ASSERT (ctx->type == _MONGOCRYPT_TYPE_ENCRYPT); BSON_ASSERT (ctx->state == MONGOCRYPT_CTX_NEED_MONGO_KEYS); mongocrypt_ctx_destroy (ctx); /* double succeeds for random. */ tmp = TEST_BSON ("{'v': { '$double': '1.23'} }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx); mongocrypt_ctx_destroy (ctx); /* double fails for deterministic. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for deterministic encryption"); mongocrypt_ctx_destroy (ctx); /* decimal128 succeeds for random. */ tmp = TEST_BSON ("{'v': {'$numberDecimal': '1.23'} }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx); mongocrypt_ctx_destroy (ctx); /* decimal128 fails for deterministic. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for deterministic encryption"); mongocrypt_ctx_destroy (ctx); /* document succeeds for random. */ tmp = TEST_BSON ("{'v': { 'x': 1 } }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx); mongocrypt_ctx_destroy (ctx); /* document fails for deterministic. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for deterministic encryption"); mongocrypt_ctx_destroy (ctx); /* array succeeds for random. */ tmp = TEST_BSON ("{'v': [1,2,3] }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx); mongocrypt_ctx_destroy (ctx); /* document fails for deterministic. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for deterministic encryption"); mongocrypt_ctx_destroy (ctx); /* codewscope succeeds for random. */ tmp = TEST_BSON ("{'v': {'$code': 'var x = 1;', '$scope': {} } }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx); mongocrypt_ctx_destroy (ctx); /* codewscope fails for deterministic. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for deterministic encryption"); mongocrypt_ctx_destroy (ctx); /* bool succeeds for random. */ tmp = TEST_BSON ("{'v': true }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx); mongocrypt_ctx_destroy (ctx); /* bool fails for deterministic. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for deterministic encryption"); mongocrypt_ctx_destroy (ctx); /* null fails for deterministic. */ tmp = TEST_BSON ("{'v': null }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for encryption"); mongocrypt_ctx_destroy (ctx); /* null fails for deterministic. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for encryption"); mongocrypt_ctx_destroy (ctx); /* minkey fails for deterministic. */ tmp = TEST_BSON ("{'v': { '$minKey': 1 } }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for encryption"); mongocrypt_ctx_destroy (ctx); /* minkey fails for deterministic. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for encryption"); mongocrypt_ctx_destroy (ctx); /* maxkey fails for deterministic. */ tmp = TEST_BSON ("{'v': { '$maxKey': 1 } }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for encryption"); mongocrypt_ctx_destroy (ctx); /* maxkey fails for deterministic. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for encryption"); mongocrypt_ctx_destroy (ctx); /* undefined fails for deterministic. */ tmp = TEST_BSON ("{'v': { '$undefined': true } }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for encryption"); mongocrypt_ctx_destroy (ctx); /* undefined fails for deterministic. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON type invalid for encryption"); mongocrypt_ctx_destroy (ctx); /* dbpointer succeeds for deterministic. */ tmp = TEST_BSON ("{'v': { '$dbPointer': {'$ref': 'ns', '$id': {'$oid': " "'AAAAAAAAAAAAAAAAAAAAAAAA'} } } }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx); mongocrypt_ctx_destroy (ctx); /* dbpointer succeeds for random. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx); mongocrypt_ctx_destroy (ctx); /* binary subtype 6 fails for deterministic. */ tmp = TEST_BSON ( "{'v': { '$binary': { 'base64': 'AAAA', 'subType': '06' } } }"); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON binary subtype 6 is invalid for encryption"); mongocrypt_ctx_destroy (ctx); /* binary subtype 6 fails for random. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, random, -1), ctx); ASSERT_FAILS (mongocrypt_ctx_explicit_encrypt_init (ctx, tmp), ctx, "BSON binary subtype 6 is invalid for encryption"); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); mongocrypt_binary_destroy (msg); mongocrypt_binary_destroy (bad_name); mongocrypt_binary_destroy (name); mongocrypt_binary_destroy (string_msg); mongocrypt_binary_destroy (no_v_msg); mongocrypt_binary_destroy (key_id); bson_destroy (bson_bad_name); bson_destroy (bson_name); bson_destroy (bson_msg); bson_destroy (bson_msg_no_v); } /* Test individual ctx states. */ static void _test_encrypt_init (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); /* Success. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); mongocrypt_ctx_destroy (ctx); /* NULL namespace. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_FAILS (mongocrypt_ctx_encrypt_init ( ctx, NULL, 0, TEST_FILE ("./test/example/cmd.json")), ctx, "invalid db"); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_ERROR); mongocrypt_ctx_destroy (ctx); /* Wrong state. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); ASSERT_FAILS (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx, "cannot double initialize"); mongocrypt_ctx_destroy (ctx); /* Empty db name is an error. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_FAILS (mongocrypt_ctx_encrypt_init ( ctx, "", -1, TEST_FILE ("./test/example/cmd.json")), ctx, "invalid db"); mongocrypt_ctx_destroy (ctx); /* Empty coll name is an error. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_FAILS ( mongocrypt_ctx_encrypt_init (ctx, "", -1, TEST_BSON ("{'find': ''}")), ctx, "empty collection name on command"); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_need_collinfo (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; /* Success. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/collection-info.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* Coll info with no schema. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* Coll info with NULL schema. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); ASSERT_FAILS (mongocrypt_ctx_mongo_feed (ctx, NULL), ctx, "invalid NULL"); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_ERROR); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* No coll info. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); /* No call to ctx_mongo_feed. */ ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* Wrong state. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_KMS); ASSERT_FAILS (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/collection-info.json")), ctx, "wrong state"); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_ERROR); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_need_markings (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_binary_t *bin; bin = mongocrypt_binary_new (); /* Success. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); mongocrypt_ctx_mongo_op (ctx, bin); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/mongocryptd-cmd.json"), bin); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_KEYS); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* Key alt name. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/mongocryptd-reply-key-alt-name.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_KEYS); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* No placeholders. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/mongocryptd-reply-no-markings.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_READY); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* No encryption in schema. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/mongocryptd-reply-no-encryption-needed.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_READY); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* Invalid marking. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_FAILS ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/mongocryptd-reply-invalid.json")), ctx, "no 'v'"); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_ERROR); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* NULL markings. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_FAILS (mongocrypt_ctx_mongo_feed (ctx, NULL), ctx, "invalid NULL"); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_ERROR); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* Wrong state. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_KMS); ASSERT_FAILS (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/mongocryptd-reply.json")), ctx, "wrong state"); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_ERROR); mongocrypt_binary_destroy (bin); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_csfle_no_needs_markings (_mongocrypt_tester_t *tester) { if (!TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB) { fputs ("No 'real' csfle library is available. The " "_test_encrypt_csfle_no_needs_markings test is a no-op.", stderr); return; } /* Success. */ mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_WITH_CRYPT_SHARED_LIB); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_KEYS); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_KEYS); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_need_keys (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; /* Success. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_KEYS); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/key-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_KMS); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ /* Did not provide all keys. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_KEYS); ASSERT_FAILS (mongocrypt_ctx_mongo_done (ctx), ctx, "not all keys requested were satisfied"); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_ERROR); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* recreate crypt because of caching. */ } static void _test_encrypt_ready (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_binary_t *encrypted_cmd; _mongocrypt_buffer_t ciphertext_buf; _mongocrypt_ciphertext_t ciphertext; bson_t as_bson; bson_iter_t iter; bool ret; mongocrypt_status_t *status; status = mongocrypt_status_new (); crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); encrypted_cmd = mongocrypt_binary_new (); ASSERT_OR_PRINT (crypt, status); /* Success. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_READY); ASSERT_OK (mongocrypt_ctx_finalize (ctx, encrypted_cmd), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_DONE); /* check that the encrypted command has a valid ciphertext. */ BSON_ASSERT (_mongocrypt_binary_to_bson (encrypted_cmd, &as_bson)); CRYPT_TRACEF (&crypt->log, "encrypted doc: %s", tmp_json (&as_bson)); bson_iter_init (&iter, &as_bson); bson_iter_find_descendant (&iter, "filter.ssn", &iter); BSON_ASSERT (BSON_ITER_HOLDS_BINARY (&iter)); BSON_ASSERT (_mongocrypt_buffer_from_binary_iter (&ciphertext_buf, &iter)); ret = _mongocrypt_ciphertext_parse_unowned ( &ciphertext_buf, &ciphertext, status); ASSERT_OR_PRINT (ret, status); /* check that encrypted command matches. */ ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/encrypted-cmd.json"), encrypted_cmd); mongocrypt_ctx_destroy (ctx); mongocrypt_binary_destroy (encrypted_cmd); mongocrypt_status_destroy (status); mongocrypt_destroy (crypt); } static void _test_key_missing_region (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_KEYS); ASSERT_FAILS (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/key-document-no-region.json")), ctx, "expected UTF-8 region"); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_ERROR); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test that attempting to auto encrypt on a view is disallowed. */ static void _test_view (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); ASSERT_FAILS (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/collection-info-view.json")), ctx, "cannot auto encrypt a view"); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_ERROR); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Check that the schema identified in the schema_map by 'ns' matches the * 'jsonSchema' of the mongocryptd command. */ static void _assert_schema_compares (mongocrypt_binary_t *schema_map, const char *ns, mongocrypt_binary_t *mongocryptd_cmd) { bson_t schema_map_bson, mongocryptd_cmd_bson, expected_schema, actual_schema; uint32_t len; const uint8_t *data; bson_iter_t iter; /* Get the schema from the map. */ BSON_ASSERT (_mongocrypt_binary_to_bson (schema_map, &schema_map_bson)); BSON_ASSERT (bson_iter_init_find (&iter, &schema_map_bson, ns)); bson_iter_document (&iter, &len, &data); bson_init_static (&expected_schema, data, len); /* Get the schema from the mongocryptd command. */ BSON_ASSERT ( _mongocrypt_binary_to_bson (mongocryptd_cmd, &mongocryptd_cmd_bson)); BSON_ASSERT ( bson_iter_init_find (&iter, &mongocryptd_cmd_bson, "jsonSchema")); bson_iter_document (&iter, &len, &data); BSON_ASSERT (bson_init_static (&actual_schema, data, len)); BSON_ASSERT (bson_equal (&expected_schema, &actual_schema)); } static void _test_local_schema (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_binary_t *schema_map, *mongocryptd_cmd; crypt = mongocrypt_new (); schema_map = TEST_FILE ("./test/data/schema-map.json"); ASSERT_OK ( mongocrypt_setopt_kms_provider_aws (crypt, "example", -1, "example", -1), crypt); ASSERT_OK (mongocrypt_setopt_schema_map (crypt, schema_map), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); /* Schema map has test.test, we should jump right to NEED_MONGO_MARKINGS */ ctx = mongocrypt_ctx_new (crypt); mongocryptd_cmd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, mongocryptd_cmd), ctx); /* We should get back the schema we gave. */ _assert_schema_compares (schema_map, "test.test", mongocryptd_cmd); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_DONE); mongocrypt_ctx_destroy (ctx); mongocrypt_binary_destroy (mongocryptd_cmd); /* Schema map has test.test2, we should jump right to NEED_MONGO_MARKINGS */ ctx = mongocrypt_ctx_new (crypt); mongocryptd_cmd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_BSON ("{'find': 'test2'}")), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, mongocryptd_cmd), ctx); /* We should get back the schema we gave. */ _assert_schema_compares (schema_map, "test.test2", mongocryptd_cmd); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_DONE); mongocrypt_ctx_destroy (ctx); mongocrypt_binary_destroy (mongocryptd_cmd); /* Database that does not match should not get from the map. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "mismatch", -1, TEST_FILE ("./test/example/cmd.json")), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); mongocrypt_ctx_destroy (ctx); /* Collection that does not match should not get from the map. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_BSON ("{'find': 'mismatch'}")), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_caches_collinfo (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; bson_t *cached_collinfo; mongocrypt_status_t *status; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); status = mongocrypt_status_new (); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/collection-info.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); /* The next ctx has the schema cached. */ BSON_ASSERT (_mongocrypt_cache_get ( &crypt->cache_collinfo, "test.test", (void **) &cached_collinfo)); BSON_ASSERT (cached_collinfo != NULL); bson_destroy (cached_collinfo); mongocrypt_ctx_destroy (ctx); /* The next context enters the NEED_MONGO_MARKINGS state immediately. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); mongocrypt_status_destroy (status); } static void _test_encrypt_caches_keys (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_DONE); mongocrypt_ctx_destroy (ctx); /* The next context skips needing keys after being supplied mark documents. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_READY); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_caches_keys_by_alt_name (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/mongocryptd-reply-key-alt-name.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_KEYS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/key-document-with-alt-name.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_READY); mongocrypt_ctx_destroy (ctx); /* The next context skips needing keys after being supplied mark documents. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/mongocryptd-reply-key-alt-name.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_READY); mongocrypt_ctx_destroy (ctx); /* But a context requesting a different key alt name does not get it from the * cache. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/mongocryptd-reply-key-alt-name2.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_MONGO_KEYS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/key-document-with-alt-name2.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_READY); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_random (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/mongocryptd-reply-random.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_DONE); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_is_remote_schema (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_binary_t *bin; bson_t as_bson; bson_iter_t iter; bin = mongocrypt_binary_new (); /* isRemoteSchema = true for a remote schema. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, bin), ctx); BSON_ASSERT (_mongocrypt_binary_to_bson (bin, &as_bson)); BSON_ASSERT (bson_iter_init_find (&iter, &as_bson, "isRemoteSchema")); BSON_ASSERT (bson_iter_bool (&iter) == true); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); /* isRemoteSchema = false for a local schema. */ crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_provider_aws (crypt, "example", -1, "example", -1), crypt); ASSERT_OK (mongocrypt_setopt_schema_map ( crypt, TEST_FILE ("./test/data/schema-map.json")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, bin), ctx); BSON_ASSERT (_mongocrypt_binary_to_bson (bin, &as_bson)); BSON_ASSERT (bson_iter_init_find (&iter, &as_bson, "isRemoteSchema")); BSON_ASSERT (bson_iter_bool (&iter) == false); mongocrypt_binary_destroy (bin); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _init_fails (_mongocrypt_tester_t *tester, const char *json, const char *msg) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_FAILS ( mongocrypt_ctx_encrypt_init (ctx, "test", -1, TEST_BSON (json)), ctx, msg); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _init_ok (_mongocrypt_tester_t *tester, const char *json) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init (ctx, "test", -1, TEST_BSON (json)), ctx); if (MONGOCRYPT_CTX_NEED_MONGO_COLLINFO == mongocrypt_ctx_state (ctx)) { mongocrypt_binary_t *filter; /* verify the collection in the filter is 'coll' */ filter = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, filter), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON (TEST_BSON ("{'name': 'coll'}"), filter); mongocrypt_binary_destroy (filter); } else { // The "create" command transitions directly to // MONGOCRYPT_CTX_NEED_MONGO_MARKINGS. ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _init_bypass (_mongocrypt_tester_t *tester, const char *json) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_binary_t *bin; bin = mongocrypt_binary_new (); crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init (ctx, "test", -1, TEST_BSON (json)), ctx); BSON_ASSERT (MONGOCRYPT_CTX_READY == mongocrypt_ctx_state (ctx)); ASSERT_OK (mongocrypt_ctx_finalize (ctx, bin), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON (TEST_BSON (json), (bin)); mongocrypt_binary_destroy (bin); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_init_each_cmd (_mongocrypt_tester_t *tester) { /* collection aggregate is ok */ _init_ok (tester, "{'aggregate': 'coll'}"); /* db agg is not ok */ _init_fails ( tester, "{'aggregate': 1}", "non-collection command not supported for auto encryption: aggregate"); _init_ok (tester, "{'count': 'coll'}"); _init_ok (tester, "{'distinct': 'coll'}"); _init_ok (tester, "{'delete': 'coll'}"); _init_ok (tester, "{'find': 'coll'}"); _init_ok (tester, "{'findAndModify': 'coll'}"); _init_bypass (tester, "{'getMore': 'coll'}"); _init_ok (tester, "{'insert': 'coll'}"); _init_ok (tester, "{'update': 'coll'}"); _init_bypass (tester, "{'authenticate': 1}"); _init_bypass (tester, "{'getnonce': 1}"); _init_bypass (tester, "{'logout': 1}"); _init_bypass (tester, "{'isMaster': 1}"); _init_bypass (tester, "{'abortTransaction': 1}"); _init_bypass (tester, "{'commitTransaction': 1}"); _init_bypass (tester, "{'endSessions': 1}"); _init_bypass (tester, "{'startSession': 1}"); _init_ok (tester, "{'create': 'coll'}"); _init_ok (tester, "{'createIndexes': 'coll'}"); _init_bypass (tester, "{'drop': 1}"); _init_bypass (tester, "{'dropDatabase': 1}"); _init_bypass (tester, "{'killCursors': 1}"); _init_bypass (tester, "{'listCollections': 1}"); _init_bypass (tester, "{'listDatabases': 1}"); _init_bypass (tester, "{'listIndexes': 1}"); _init_bypass (tester, "{'renameCollection': 'coll'}"); _init_ok (tester, "{'explain': { 'find': 'coll' }}"); _init_fails (tester, "{'explain': { } }", "invalid empty BSON"); _init_fails (tester, "{'explain': { 'aggregate': 1 }}", "non-collection command not supported for auto encryption"); _init_bypass (tester, "{'ping': 1}"); _init_bypass (tester, "{'saslStart': 1}"); _init_bypass (tester, "{'saslContinue': 1}"); _init_fails (tester, "{'fakecmd': 'coll'}", "command not supported for auto encryption: fakecmd"); /* fails for eligible command with no collection name. */ _init_fails ( tester, "{'insert': 1}", "non-collection command not supported for auto encryption: insert"); _init_fails (tester, "{}", "unexpected empty BSON for command"); _init_bypass (tester, "{'isMaster': 1}"); _init_bypass (tester, "{'ismaster': 1}"); _init_bypass (tester, "{'killAllSessions': 1}"); _init_bypass (tester, "{'killSessions': 1}"); _init_bypass (tester, "{'killAllSessionsByPattern': 1}"); _init_bypass (tester, "{'refreshSessions': 1}"); _init_ok (tester, "{'compactStructuredEncryptionData': 'coll'}"); _init_bypass (tester, "{'hello': 1}"); _init_bypass (tester, "{'buildInfo': 1}"); _init_bypass (tester, "{'getCmdLineOpts': 1}"); _init_bypass (tester, "{'getLog': 1}"); _init_ok (tester, "{'collMod': 'coll'}"); } static void _test_encrypt_invalid_siblings (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); BSON_ASSERT (MONGOCRYPT_CTX_NEED_MONGO_COLLINFO == mongocrypt_ctx_state (ctx)); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/collinfo-siblings.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (MONGOCRYPT_CTX_NEED_MONGO_MARKINGS == mongocrypt_ctx_state (ctx)); ASSERT_FAILS (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/mongocryptd-reply.json")), ctx, "JSON schema validator has siblings"); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_dupe_jsonschema (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); BSON_ASSERT (MONGOCRYPT_CTX_NEED_MONGO_COLLINFO == mongocrypt_ctx_state (ctx)); ASSERT_FAILS (mongocrypt_ctx_mongo_feed ( ctx, TEST_BSON ("{'options': {'validator': { '$jsonSchema': {}, " "'$jsonSchema': {} } } }")), ctx, "duplicate $jsonSchema"); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypting_with_explicit_encryption (_mongocrypt_tester_t *tester) { /* Test that we do not strip existing ciphertexts when automatically * encrypting a document. */ mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_binary_t *bin; bson_iter_t iter; bson_t tmp; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/mongocryptd-reply-existing-ciphertext.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_READY); bin = mongocrypt_binary_new (); mongocrypt_ctx_finalize (ctx, bin); BSON_ASSERT (_mongocrypt_binary_to_bson (bin, &tmp)); BSON_ASSERT (bson_iter_init (&iter, &tmp)); BSON_ASSERT ( bson_iter_find_descendant (&iter, "filter.existing_ciphertext", &iter)); mongocrypt_binary_destroy (bin); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_explicit_encryption (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; _mongocrypt_buffer_t from_key_id, from_key_altname; mongocrypt_binary_t *bin, *key_id; char *deterministic = MONGOCRYPT_ALGORITHM_DETERMINISTIC_STR; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); key_id = mongocrypt_binary_new_from_data ( MONGOCRYPT_DATA_AND_LEN ("aaaaaaaaaaaaaaaa")); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_OK (mongocrypt_ctx_setopt_key_id (ctx, key_id), ctx); ASSERT_OK ( mongocrypt_ctx_explicit_encrypt_init (ctx, TEST_BSON ("{'v': 123}")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_READY); bin = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, bin), ctx); _mongocrypt_buffer_copy_from_binary (&from_key_id, bin); mongocrypt_binary_destroy (bin); mongocrypt_binary_destroy (key_id); mongocrypt_ctx_destroy (ctx); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, deterministic, -1), ctx); ASSERT_OK (mongocrypt_ctx_setopt_key_alt_name ( ctx, TEST_BSON ("{'keyAltName': 'keyDocumentName'}")), ctx); ASSERT_OK ( mongocrypt_ctx_explicit_encrypt_init (ctx, TEST_BSON ("{'v': 123}")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_READY); bin = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, bin), ctx); _mongocrypt_buffer_copy_from_binary (&from_key_altname, bin); mongocrypt_binary_destroy (bin); mongocrypt_ctx_destroy (ctx); BSON_ASSERT (0 == _mongocrypt_buffer_cmp (&from_key_id, &from_key_altname)); _mongocrypt_buffer_cleanup (&from_key_id); _mongocrypt_buffer_cleanup (&from_key_altname); mongocrypt_destroy (crypt); } /* Test with empty AWS credentials. */ void _test_encrypt_empty_aws (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = mongocrypt_new (); ASSERT_OK (mongocrypt_setopt_kms_provider_aws (crypt, "", -1, "", -1), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_KEYS); ASSERT_FAILS (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/key-document.json")), ctx, "failed to create KMS message"); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_custom_endpoint (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_kms_ctx_t *kms_ctx; mongocrypt_binary_t *bin; const char *endpoint; /* Success. */ crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_KEYS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/key-document-custom-endpoint.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_KMS); kms_ctx = mongocrypt_ctx_next_kms_ctx (ctx); BSON_ASSERT (kms_ctx); ASSERT_OK (mongocrypt_kms_ctx_endpoint (kms_ctx, &endpoint), ctx); BSON_ASSERT (0 == strcmp ("example.com:443", endpoint)); bin = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_kms_ctx_message (kms_ctx, bin), ctx); BSON_ASSERT (NULL != strstr ((char *) bin->data, "Host:example.com")); mongocrypt_binary_destroy (bin); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_per_ctx_credentials (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_kms_ctx_t *kms_ctx; mongocrypt_binary_t *bin; const char *endpoint; /* Success. */ crypt = mongocrypt_new (); mongocrypt_setopt_use_need_kms_credentials_state (crypt); mongocrypt_setopt_kms_providers (crypt, TEST_BSON ("{'aws': {}}")); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS); ASSERT_OK (mongocrypt_ctx_provide_kms_providers ( ctx, TEST_BSON ("{'aws':{'accessKeyId': 'example'," "'secretAccessKey': 'example'}}")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_KEYS); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/example/key-document-custom-endpoint.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); BSON_ASSERT (mongocrypt_ctx_state (ctx) == MONGOCRYPT_CTX_NEED_KMS); kms_ctx = mongocrypt_ctx_next_kms_ctx (ctx); BSON_ASSERT (kms_ctx); ASSERT_OK (mongocrypt_kms_ctx_endpoint (kms_ctx, &endpoint), ctx); BSON_ASSERT (0 == strcmp ("example.com:443", endpoint)); bin = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_kms_ctx_message (kms_ctx, bin), ctx); BSON_ASSERT (NULL != strstr ((char *) bin->data, "Host:example.com")); mongocrypt_binary_destroy (bin); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } // Regression test for MONGOCRYPT-488. static void _test_encrypt_per_ctx_credentials_given_empty (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = mongocrypt_new (); mongocrypt_setopt_use_need_kms_credentials_state (crypt); mongocrypt_setopt_kms_providers (crypt, TEST_BSON ("{'aws': {}}")); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS); ASSERT_FAILS (mongocrypt_ctx_provide_kms_providers (ctx, TEST_BSON ("{}")), ctx, "no kms provider set"); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_ERROR); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_per_ctx_credentials_local (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; /* local_kek is the KEK used to encrypt the keyMaterial in * ./test/data/key-document-local.json */ const char *local_kek = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; crypt = mongocrypt_new (); mongocrypt_setopt_use_need_kms_credentials_state (crypt); mongocrypt_setopt_kms_providers (crypt, TEST_BSON ("{'local': {}}")); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS); ASSERT_OK (mongocrypt_ctx_provide_kms_providers ( ctx, TEST_BSON ("{'local':{'key': { '$binary': {'base64': '%s', " "'subType': '00'}}}}", local_kek)), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_KEYS); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/key-document-local.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_with_aws_session_token (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_binary_t *bin; mongocrypt_ctx_t *ctx; mongocrypt_kms_ctx_t *kms_ctx; char *http_req; crypt = mongocrypt_new (); ASSERT_OK (mongocrypt_setopt_kms_providers ( crypt, TEST_BSON ("{'aws': {'sessionToken': 'mySessionToken', " "'accessKeyId': 'myAccessKeyId', " "'secretAccessKey': 'mySecretAccessKey'}}")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_NEED_KMS); kms_ctx = mongocrypt_ctx_next_kms_ctx (ctx); BSON_ASSERT (NULL != kms_ctx); bin = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_kms_ctx_message (kms_ctx, bin), kms_ctx); http_req = (char *) mongocrypt_binary_data (bin); ASSERT_STRCONTAINS (http_req, "X-Amz-Security-Token:mySessionToken"); mongocrypt_binary_destroy (bin); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_caches_empty_collinfo (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); /* Do not feed anything for collinfo. */ ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_DONE); mongocrypt_ctx_destroy (ctx); /* Create another encryption context on the same namespace test.test. It * should not transition to the MONGOCRYPT_CTX_NEED_MONGO_COLLINFO state. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_DONE); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_caches_collinfo_without_jsonschema (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/collection-info-no-validator.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_DONE); mongocrypt_ctx_destroy (ctx); /* Create another encryption context on the same namespace test.test. It * should not transition to the MONGOCRYPT_CTX_NEED_MONGO_COLLINFO state. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "test", -1, TEST_FILE ("./test/example/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); _mongocrypt_tester_run_ctx_to (tester, ctx, MONGOCRYPT_CTX_DONE); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_with_encrypted_field_config_map (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_providers ( crypt, TEST_BSON ( "{'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'bar'}}")), crypt); ASSERT_OK (mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_BSON ("{'db.coll': {'fields': []}}")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); /* Test encrypting a command on a collection present in the encrypted field * config map. */ ctx = mongocrypt_ctx_new (crypt); ASSERT_OK ( mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-find-explicit/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd; cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-find-explicit/cmd-to-mongocryptd.json"), cmd_to_mongocryptd); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/fle2-find-explicit/reply-from-mongocryptd.json")), ctx); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *cmd_to_mongod; cmd_to_mongod = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, cmd_to_mongod), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-find-explicit/cmd-to-mongod.json"), cmd_to_mongod); mongocrypt_binary_destroy (cmd_to_mongod); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test encrypting a bypassed command on a collection present in the encrypted * field config map. Expect no encryptionInformation. */ static void _test_encrypt_with_encrypted_field_config_map_bypassed ( _mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_providers ( crypt, TEST_BSON ( "{'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'bar'}}")), crypt); ASSERT_OK (mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_BSON ("{'db.coll': {'fields': []}}")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); /* 'drop' is bypassed. Expect that no 'encryptionInformation' is appended. */ ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_BSON ("{'drop': 'coll'}")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *cmd_to_mongod; cmd_to_mongod = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, cmd_to_mongod), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON (TEST_BSON ("{'drop': 'coll'}"), cmd_to_mongod); mongocrypt_binary_destroy (cmd_to_mongod); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test that an empty jsonSchema document is appended to the command sent to * mongocryptd when no encryptedFieldConfig or jsonSchema is found for the * collection. * * This is a regression test for PYTHON-3188. */ static void _test_encrypt_no_schema (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK ( mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_BSON ("{'find': 'collection_without_schema', 'filter': {}}")), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); /* Give no collection info. */ ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); _mongocrypt_tester_run_ctx_to ( tester, ctx, MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd; cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_BSON ("{'find': 'collection_without_schema', 'filter': {}, " "'jsonSchema': {}, 'isRemoteSchema': true}"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_encrypt_remote_encryptedfields (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_providers ( crypt, TEST_BSON ( "{'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'bar'}}")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); /* Test success. */ { ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-find-explicit/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_BSON ("{'name': 'coll', 'options': " "{'encryptedFields': {'fields': []}}}")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } /* Check that command to mongocryptd includes "encryptionInformation". */ ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); /* "encryptionInformation.schema" must be the document from * "encryptedFields" fed from MONGOCRYPT_CTX_NEED_MONGO_COLLINFO. */ ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle2-find-explicit/cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } mongocrypt_ctx_destroy (ctx); } /* Test that the previous 'encryptedFields' is cached. */ { ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-find-explicit/cmd.json")), ctx); /* Check that command to mongocryptd includes "encryptionInformation". */ ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); /* "encryptionInformation.schema" must be the document from * "encryptedFields" fed from MONGOCRYPT_CTX_NEED_MONGO_COLLINFO. */ ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle2-find-explicit/cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } mongocrypt_ctx_destroy (ctx); } /* Test that "encryptedFields" is preferred over "$jsonSchema". */ { /* Recreate crypt to clear cache. */ mongocrypt_destroy (crypt); crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_providers ( crypt, TEST_BSON ( "{'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'bar'}}")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-find-explicit/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_BSON ( "{'name': 'coll', 'options': { 'validator': { '$jsonSchema': " "{'baz': 'qux' }}, 'encryptedFields': {'fields': []}}}")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } /* Check that command to mongocryptd includes "encryptionInformation". */ ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd; cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); /* "encryptionInformation.schema" must be the document from * "encryptedFields" fed from MONGOCRYPT_CTX_NEED_MONGO_COLLINFO. */ ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle2-find-explicit/cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } mongocrypt_ctx_destroy (ctx); } mongocrypt_destroy (crypt); } static void _test_encrypt_with_bypassqueryanalysis (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; /* Test with EncryptedFieldConfig from map. */ { crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_providers ( crypt, TEST_BSON ( "{'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'bar'}}")), crypt); ASSERT_OK (mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_BSON ("{'db.coll': {'fields': []}}")), crypt); mongocrypt_setopt_bypass_query_analysis (crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-find-explicit/cmd.json")), ctx); /* Should transition directly to ready. */ ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *cmd_to_mongod = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, cmd_to_mongod), ctx); /* "encryptionInformation" must be present. */ ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-find-explicit/cmd-to-mongod.json"), cmd_to_mongod); mongocrypt_binary_destroy (cmd_to_mongod); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test with EncryptedFieldConfig from listCollections. */ { crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_providers ( crypt, TEST_BSON ( "{'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'bar'}}")), crypt); mongocrypt_setopt_bypass_query_analysis (crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-find-explicit/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_BSON ("{'options': {'encryptedFields': {'fields': []}}}")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *cmd_to_mongod = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, cmd_to_mongod), ctx); /* "encryptionInformation" must be present. */ ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-find-explicit/cmd-to-mongod.json"), cmd_to_mongod); mongocrypt_binary_destroy (cmd_to_mongod); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } } static void _test_FLE2EncryptionPlaceholder_parse (_mongocrypt_tester_t *tester) { mc_FLE2EncryptionPlaceholder_t placeholder; bson_t as_bson; mongocrypt_status_t *status; _mongocrypt_buffer_t buf; status = mongocrypt_status_new (); _mongocrypt_buffer_copy_from_hex ( &buf, "03610000001074000100000010610002000000056b690010000000041234567812349876" "1234123456789012056b75001000000004abcdefab123498761234123456789012027600" "0900000076616c75653132330012636d00000000000000000000"); ASSERT (bson_init_static (&as_bson, buf.data + 1, buf.len - 1)); mc_FLE2EncryptionPlaceholder_init (&placeholder); ASSERT_OK_STATUS ( mc_FLE2EncryptionPlaceholder_parse (&placeholder, &as_bson, status), status); ASSERT (placeholder.type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT); ASSERT (placeholder.algorithm == MONGOCRYPT_FLE2_ALGORITHM_EQUALITY); ASSERT (BSON_ITER_HOLDS_UTF8 (&placeholder.v_iter)); ASSERT_STREQUAL (bson_iter_utf8 (&placeholder.v_iter, NULL), "value123"); _mongocrypt_buffer_t expect_index_key_id; _mongocrypt_buffer_copy_from_hex (&expect_index_key_id, "12345678123498761234123456789012"); ASSERT_CMPBUF (placeholder.index_key_id, expect_index_key_id); _mongocrypt_buffer_cleanup (&expect_index_key_id); _mongocrypt_buffer_t expect_user_key_id; _mongocrypt_buffer_copy_from_hex (&expect_user_key_id, "abcdefab123498761234123456789012"); ASSERT_CMPBUF (placeholder.user_key_id, expect_user_key_id); _mongocrypt_buffer_cleanup (&expect_user_key_id); ASSERT (placeholder.maxContentionCounter == 0); mc_FLE2EncryptionPlaceholder_cleanup (&placeholder); _mongocrypt_buffer_cleanup (&buf); mongocrypt_status_destroy (status); } static void _test_FLE2EncryptionPlaceholder_range_parse (_mongocrypt_tester_t *tester) { // Test type=MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT. { mc_FLE2EncryptionPlaceholder_t placeholder; bson_t as_bson; mongocrypt_status_t *status; _mongocrypt_buffer_t buf; status = mongocrypt_status_new (); _mongocrypt_buffer_copy_from_hex ( &buf, "037d0000001074000100000010610003000000056b690010000000041234567812349" "8761234123456789012056b75001000000004abcdefab123498761234123456789012" "0376001e00000010760040e20100106d696e0000000000106d61780087d6120000126" "36d000000000000000000127300010000000000000000"); ASSERT (bson_init_static (&as_bson, buf.data + 1, buf.len - 1)); mc_FLE2EncryptionPlaceholder_init (&placeholder); ASSERT_OK_STATUS ( mc_FLE2EncryptionPlaceholder_parse (&placeholder, &as_bson, status), status); ASSERT (placeholder.type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT); ASSERT (placeholder.algorithm == MONGOCRYPT_FLE2_ALGORITHM_RANGE); _mongocrypt_buffer_t expect_index_key_id; _mongocrypt_buffer_copy_from_hex (&expect_index_key_id, "12345678123498761234123456789012"); ASSERT_CMPBUF (placeholder.index_key_id, expect_index_key_id); _mongocrypt_buffer_cleanup (&expect_index_key_id); _mongocrypt_buffer_t expect_user_key_id; _mongocrypt_buffer_copy_from_hex (&expect_user_key_id, "abcdefab123498761234123456789012"); ASSERT_CMPBUF (placeholder.user_key_id, expect_user_key_id); _mongocrypt_buffer_cleanup (&expect_user_key_id); ASSERT_CMPINT64 (placeholder.sparsity, ==, 1); // Parse FLE2RangeInsertSpec. { mc_FLE2RangeInsertSpec_t spec; ASSERT_OK_STATUS ( mc_FLE2RangeInsertSpec_parse (&spec, &placeholder.v_iter, status), status); ASSERT (BSON_ITER_HOLDS_INT32 (&spec.v)); ASSERT_CMPINT32 (bson_iter_int32 (&spec.v), ==, 123456); ASSERT (BSON_ITER_HOLDS_INT32 (&spec.min)); ASSERT_CMPINT32 (bson_iter_int32 (&spec.min), ==, 0); ASSERT (BSON_ITER_HOLDS_INT32 (&spec.max)); ASSERT_CMPINT32 (bson_iter_int32 (&spec.max), ==, 1234567); } mc_FLE2EncryptionPlaceholder_cleanup (&placeholder); _mongocrypt_buffer_cleanup (&buf); mongocrypt_status_destroy (status); } // Test type=MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND. { mc_FLE2EncryptionPlaceholder_t placeholder; bson_t as_bson; mongocrypt_status_t *status; _mongocrypt_buffer_t buf; status = mongocrypt_status_new (); _mongocrypt_buffer_copy_from_hex ( &buf, "03ec0000001074000200000010610003000000056b690010000000041234567812349" "8761234123456789012056b75001000000004abcdefab123498761234123456789012" "0376008d000000036564676573496e666f005b000000106c6f776572426f756e64000" "0000000086c62496e636c756465640001107570706572426f756e640087d612000875" "62496e636c75646564000110696e6465784d696e000000000010696e6465784d61780" "087d6120000107061796c6f6164496400d20400001066697273744f70657261746f72" "00010000000012636d000000000000000000127300010000000000000000"); ASSERT (bson_init_static (&as_bson, buf.data + 1, buf.len - 1)); mc_FLE2EncryptionPlaceholder_init (&placeholder); ASSERT_OK_STATUS ( mc_FLE2EncryptionPlaceholder_parse (&placeholder, &as_bson, status), status); ASSERT (placeholder.type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND); ASSERT (placeholder.algorithm == MONGOCRYPT_FLE2_ALGORITHM_RANGE); _mongocrypt_buffer_t expect_index_key_id; _mongocrypt_buffer_copy_from_hex (&expect_index_key_id, "12345678123498761234123456789012"); ASSERT_CMPBUF (placeholder.index_key_id, expect_index_key_id); _mongocrypt_buffer_cleanup (&expect_index_key_id); _mongocrypt_buffer_t expect_user_key_id; _mongocrypt_buffer_copy_from_hex (&expect_user_key_id, "abcdefab123498761234123456789012"); ASSERT_CMPBUF (placeholder.user_key_id, expect_user_key_id); _mongocrypt_buffer_cleanup (&expect_user_key_id); ASSERT_CMPINT64 (placeholder.sparsity, ==, 1); // Parse FLE2RangeFindSpec. { mc_FLE2RangeFindSpec_t spec; ASSERT_OK_STATUS ( mc_FLE2RangeFindSpec_parse (&spec, &placeholder.v_iter, status), status); ASSERT (spec.edgesInfo.set); ASSERT (BSON_ITER_HOLDS_INT32 (&spec.edgesInfo.value.lowerBound)); ASSERT_CMPINT32 ( bson_iter_int32 (&spec.edgesInfo.value.lowerBound), ==, 0); ASSERT (spec.edgesInfo.value.lbIncluded); ASSERT (BSON_ITER_HOLDS_INT32 (&spec.edgesInfo.value.upperBound)); ASSERT_CMPINT32 ( bson_iter_int32 (&spec.edgesInfo.value.upperBound), ==, 1234567); ASSERT (spec.edgesInfo.value.ubIncluded); ASSERT (BSON_ITER_HOLDS_INT32 (&spec.edgesInfo.value.indexMin)); ASSERT_CMPINT32 ( bson_iter_int32 (&spec.edgesInfo.value.indexMin), ==, 0); ASSERT (spec.edgesInfo.value.ubIncluded); ASSERT (BSON_ITER_HOLDS_INT32 (&spec.edgesInfo.value.indexMax)); ASSERT_CMPINT32 ( bson_iter_int32 (&spec.edgesInfo.value.indexMax), ==, 1234567); ASSERT (spec.edgesInfo.value.ubIncluded); ASSERT_CMPINT32 (spec.payloadId, ==, 1234); ASSERT_CMPINT (spec.firstOperator, ==, FLE2RangeOperator_kGt); ASSERT_CMPINT (spec.secondOperator, ==, FLE2RangeOperator_kNone); } mc_FLE2EncryptionPlaceholder_cleanup (&placeholder); _mongocrypt_buffer_cleanup (&buf); mongocrypt_status_destroy (status); } // Test type=MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND with precision. { mc_FLE2EncryptionPlaceholder_t placeholder; bson_t as_bson; mongocrypt_status_t *status; _mongocrypt_buffer_t buf; status = mongocrypt_status_new (); _mongocrypt_buffer_copy_from_hex ( &buf, "030b0100001074000200000010610003000000056b690010000000041234567812349" "8761234123456789012056b75001000000004abcdefab123498761234123456789012" "037600ac000000036564676573496e666f007a000000016c6f776572426f756e64000" "000000000000000086c62496e636c756465640001017570706572426f756e64000000" "000000006940087562496e636c75646564000110707265636973696f6e00020000000" "1696e6465784d696e00000000000000000001696e6465784d61780000000000000069" "4000107061796c6f6164496400d20400001066697273744f70657261746f720001000" "0000012636d000000000000000000127300010000000000000000"); ASSERT (bson_init_static (&as_bson, buf.data + 1, buf.len - 1)); mc_FLE2EncryptionPlaceholder_init (&placeholder); ASSERT_OK_STATUS ( mc_FLE2EncryptionPlaceholder_parse (&placeholder, &as_bson, status), status); ASSERT (placeholder.type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND); ASSERT (placeholder.algorithm == MONGOCRYPT_FLE2_ALGORITHM_RANGE); _mongocrypt_buffer_t expect_index_key_id; _mongocrypt_buffer_copy_from_hex (&expect_index_key_id, "12345678123498761234123456789012"); ASSERT_CMPBUF (placeholder.index_key_id, expect_index_key_id); _mongocrypt_buffer_cleanup (&expect_index_key_id); _mongocrypt_buffer_t expect_user_key_id; _mongocrypt_buffer_copy_from_hex (&expect_user_key_id, "abcdefab123498761234123456789012"); ASSERT_CMPBUF (placeholder.user_key_id, expect_user_key_id); _mongocrypt_buffer_cleanup (&expect_user_key_id); ASSERT_CMPINT64 (placeholder.sparsity, ==, 1); // Parse FLE2RangeFindSpec. { mc_FLE2RangeFindSpec_t spec; ASSERT_OK_STATUS ( mc_FLE2RangeFindSpec_parse (&spec, &placeholder.v_iter, status), status); ASSERT (spec.edgesInfo.set); ASSERT (BSON_ITER_HOLDS_DOUBLE (&spec.edgesInfo.value.lowerBound)); ASSERT_CMPDOUBLE ( bson_iter_double (&spec.edgesInfo.value.lowerBound), ==, 0.0); ASSERT (spec.edgesInfo.value.lbIncluded); ASSERT (BSON_ITER_HOLDS_DOUBLE (&spec.edgesInfo.value.upperBound)); ASSERT_CMPDOUBLE ( bson_iter_double (&spec.edgesInfo.value.upperBound), ==, 200.0); ASSERT (spec.edgesInfo.value.ubIncluded); ASSERT (BSON_ITER_HOLDS_DOUBLE (&spec.edgesInfo.value.indexMin)); ASSERT_CMPDOUBLE ( bson_iter_double (&spec.edgesInfo.value.indexMin), ==, 0); ASSERT (spec.edgesInfo.value.ubIncluded); ASSERT (BSON_ITER_HOLDS_DOUBLE (&spec.edgesInfo.value.indexMax)); ASSERT_CMPDOUBLE ( bson_iter_double (&spec.edgesInfo.value.indexMax), ==, 200.0); ASSERT (spec.edgesInfo.value.ubIncluded); ASSERT_CMPDOUBLE (spec.payloadId, ==, 1234); ASSERT_CMPINT (spec.firstOperator, ==, FLE2RangeOperator_kGt); ASSERT (spec.edgesInfo.value.precision.set); ASSERT_CMPUINT32 (spec.edgesInfo.value.precision.value, ==, 2); } mc_FLE2EncryptionPlaceholder_cleanup (&placeholder); _mongocrypt_buffer_cleanup (&buf); mongocrypt_status_destroy (status); } // Test type=MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT with precision. { mc_FLE2EncryptionPlaceholder_t placeholder; bson_t as_bson; mongocrypt_status_t *status; _mongocrypt_buffer_t buf; status = mongocrypt_status_new (); _mongocrypt_buffer_copy_from_hex ( &buf, "03980000001074000100000010610003000000056b690010000000041234567812349" "8761234123456789012056b75001000000004abcdefab123498761234123456789012" "0376003900000001760077be9f1a2fdd5e40016d696e000000000000000000016d617" "800000000000000694010707265636973696f6e00020000000012636d000000000000" "000000127300010000000000000000"); ASSERT (bson_init_static (&as_bson, buf.data + 1, buf.len - 1)); mc_FLE2EncryptionPlaceholder_init (&placeholder); ASSERT_OK_STATUS ( mc_FLE2EncryptionPlaceholder_parse (&placeholder, &as_bson, status), status); ASSERT (placeholder.type == MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_INSERT); ASSERT (placeholder.algorithm == MONGOCRYPT_FLE2_ALGORITHM_RANGE); _mongocrypt_buffer_t expect_index_key_id; _mongocrypt_buffer_copy_from_hex (&expect_index_key_id, "12345678123498761234123456789012"); ASSERT_CMPBUF (placeholder.index_key_id, expect_index_key_id); _mongocrypt_buffer_cleanup (&expect_index_key_id); _mongocrypt_buffer_t expect_user_key_id; _mongocrypt_buffer_copy_from_hex (&expect_user_key_id, "abcdefab123498761234123456789012"); ASSERT_CMPBUF (placeholder.user_key_id, expect_user_key_id); _mongocrypt_buffer_cleanup (&expect_user_key_id); ASSERT_CMPINT64 (placeholder.sparsity, ==, 1); // Parse FLE2RangeInsertSpec. { mc_FLE2RangeInsertSpec_t spec; ASSERT_OK_STATUS ( mc_FLE2RangeInsertSpec_parse (&spec, &placeholder.v_iter, status), status); ASSERT (BSON_ITER_HOLDS_DOUBLE (&spec.v)); ASSERT_CMPDOUBLE (bson_iter_double (&spec.v), ==, 123.456); ASSERT (BSON_ITER_HOLDS_DOUBLE (&spec.min)); ASSERT_CMPDOUBLE (bson_iter_double (&spec.min), ==, 0.0); ASSERT (BSON_ITER_HOLDS_DOUBLE (&spec.max)); ASSERT_CMPDOUBLE (bson_iter_double (&spec.max), ==, 200.0); ASSERT (spec.precision.set); ASSERT_CMPUINT32 (spec.precision.value, ==, 2); } mc_FLE2EncryptionPlaceholder_cleanup (&placeholder); _mongocrypt_buffer_cleanup (&buf); mongocrypt_status_destroy (status); } } // Shared implementation for insert and find tests typedef struct { _mongocrypt_buffer_t buf; int pos; } _test_rng_data_source; static bool _test_rng_source (void *ctx, mongocrypt_binary_t *out, uint32_t count, mongocrypt_status_t *status) { _test_rng_data_source *source = (_test_rng_data_source *) ctx; if ((source->pos + count) > source->buf.len) { TEST_ERROR ("Out of random data, wanted: %" PRIu32, count); return false; } memcpy (out->data, source->buf.data + source->pos, count); source->pos += count; return true; } static void _test_encrypt_fle2_encryption_placeholder (_mongocrypt_tester_t *tester, const char *data_path, _test_rng_data_source *rng_source) { mongocrypt_t *crypt; char pathbuf[2048]; #define MAKE_PATH(path) \ ASSERT (snprintf ( \ pathbuf, sizeof (pathbuf), "./test/data/%s/" path, data_path) < \ sizeof (pathbuf)) if (!_aes_ctr_is_supported_by_os) { printf ("Common Crypto with no CTR support detected. Skipping."); return; } /* Create crypt with custom hooks. */ { /* localkey_data is the KEK used to encrypt the keyMaterial * in ./test/data/keys/ */ char localkey_data[MONGOCRYPT_KEY_LEN] = {0}; mongocrypt_binary_t *localkey; crypt = mongocrypt_new (); mongocrypt_setopt_log_handler (crypt, _mongocrypt_stdout_log_fn, NULL); localkey = mongocrypt_binary_new_from_data ((uint8_t *) localkey_data, sizeof localkey_data); ASSERT_OK (mongocrypt_setopt_kms_provider_local (crypt, localkey), crypt); ASSERT_OK (mongocrypt_setopt_crypto_hooks ( crypt, _std_hook_native_crypto_aes_256_cbc_encrypt, _std_hook_native_crypto_aes_256_cbc_decrypt, _test_rng_source, _std_hook_native_hmac_sha512, _std_hook_native_hmac_sha256, _error_hook_native_sha256, rng_source /* ctx */), crypt); MAKE_PATH ("encrypted-field-map.json"); ASSERT_OK (mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_FILE (pathbuf)), crypt); mongocrypt_binary_destroy (localkey); ASSERT_OK (mongocrypt_init (crypt), crypt); } /* Create encryption context. */ mongocrypt_ctx_t *ctx; { ctx = mongocrypt_ctx_new (crypt); MAKE_PATH ("cmd.json"); ASSERT_OK ( mongocrypt_ctx_encrypt_init (ctx, "db", -1, TEST_FILE (pathbuf)), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { /* Use a FLE2EncryptionPlaceholder obtained from * https://gist.github.com/kevinAlbs/cba611fe0d120b3f67c6bee3195d4ce6. */ MAKE_PATH ("mongocryptd-reply.json"); ASSERT_OK (mongocrypt_ctx_mongo_feed (ctx, TEST_FILE (pathbuf)), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } #define TEST_KEY_FILE(name) \ TEST_FILE ("./test/data/keys/" name \ "123498761234123456789012-local-document.json") ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK (mongocrypt_ctx_mongo_feed (ctx, TEST_KEY_FILE ("12345678")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_feed (ctx, TEST_KEY_FILE ("ABCDEFAB")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } #undef TEST_KEY_FILE ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out; out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); MAKE_PATH ("encrypted-payload.json"); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON (TEST_FILE (pathbuf), out); mongocrypt_binary_destroy (out); } #undef MAKE_PATH mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* First 16 bytes are IV for 'p' field in FLE2InsertUpdatePayload * Second 16 bytes are IV for 'v' field in FLE2InsertUpdatePayload */ #define RNG_DATA \ "\xc7\x43\xd6\x75\x76\x9e\xa7\x88\xd5\xe5\xc4\x40\xdb\x24\x0d\xf9" \ "\x4c\xd9\x64\x10\x43\x81\xe6\x61\xfa\x1f\xa0\x5c\x49\x8e\xad\x21" static void _test_encrypt_fle2_insert_payload (_mongocrypt_tester_t *tester) { uint8_t rng_data[] = RNG_DATA; _test_rng_data_source source = { .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; _test_encrypt_fle2_encryption_placeholder (tester, "fle2-insert", &source); } #undef RNG_DATA // FLE2FindEqualityPayload only uses deterministic token generation. static void _test_encrypt_fle2_find_payload (_mongocrypt_tester_t *tester) { _test_rng_data_source source = {{0}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-find-equality", &source); } /* 16 bytes of random data are used for IV. This IV produces the expected test * ciphertext. */ #define RNG_DATA \ "\x4d\x06\x95\x64\xf5\xa0\x5e\x9e\x35\x23\xb9\x8f\x57\x5a\xcb\x15" static void _test_encrypt_fle2_unindexed_encrypted_payload (_mongocrypt_tester_t *tester) { uint8_t rng_data[] = RNG_DATA; _test_rng_data_source source = { .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-insert-unindexed", &source); } #undef RNG_DATA #include "./data/fle2-insert-range/int32/RNG_DATA.h" static void _test_encrypt_fle2_insert_range_payload_int32 (_mongocrypt_tester_t *tester) { uint8_t rng_data[] = RNG_DATA; _test_rng_data_source source = { .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-insert-range/int32", &source); } #undef RNG_DATA #include "./data/fle2-insert-range/int64/RNG_DATA.h" static void _test_encrypt_fle2_insert_range_payload_int64 (_mongocrypt_tester_t *tester) { uint8_t rng_data[] = RNG_DATA; _test_rng_data_source source = { .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-insert-range/int64", &source); } #undef RNG_DATA #include "./data/fle2-insert-range/date/RNG_DATA.h" static void _test_encrypt_fle2_insert_range_payload_date (_mongocrypt_tester_t *tester) { uint8_t rng_data[] = RNG_DATA; _test_rng_data_source source = { .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-insert-range/date", &source); } #undef RNG_DATA #include "./data/fle2-insert-range/double/RNG_DATA.h" static void _test_encrypt_fle2_insert_range_payload_double (_mongocrypt_tester_t *tester) { uint8_t rng_data[] = RNG_DATA; _test_rng_data_source source = { .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-insert-range/double", &source); } #undef RNG_DATA #include "./data/fle2-insert-range/double-precision/RNG_DATA.h" static void _test_encrypt_fle2_insert_range_payload_double_precision ( _mongocrypt_tester_t *tester) { uint8_t rng_data[] = RNG_DATA; _test_rng_data_source source = { .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-insert-range/double-precision", &source); } #undef RNG_DATA #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT #include "./data/fle2-insert-range/decimal128/RNG_DATA.h" static void _test_encrypt_fle2_insert_range_payload_decimal128 ( _mongocrypt_tester_t *tester) { uint8_t rng_data[] = RNG_DATA; _test_rng_data_source source = { .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-insert-range/decimal128", &source); } #undef RNG_DATA #include "./data/fle2-insert-range/decimal128-precision/RNG_DATA.h" static void _test_encrypt_fle2_insert_range_payload_decimal128_precision ( _mongocrypt_tester_t *tester) { uint8_t rng_data[] = RNG_DATA; _test_rng_data_source source = { .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-insert-range/decimal128-precision", &source); } #undef RNG_DATA #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT // FLE2FindRangePayload only uses deterministic token generation. static void _test_encrypt_fle2_find_range_payload_int32 (_mongocrypt_tester_t *tester) { _test_rng_data_source source = {{0}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-find-range/int32", &source); } // FLE2FindRangePayload only uses deterministic token generation. static void _test_encrypt_fle2_find_range_payload_int64 (_mongocrypt_tester_t *tester) { _test_rng_data_source source = {{0}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-find-range/int64", &source); } // FLE2FindRangePayload only uses deterministic token generation. static void _test_encrypt_fle2_find_range_payload_date (_mongocrypt_tester_t *tester) { _test_rng_data_source source = {{0}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-find-range/date", &source); } // FLE2FindRangePayload only uses deterministic token generation. static void _test_encrypt_fle2_find_range_payload_double (_mongocrypt_tester_t *tester) { _test_rng_data_source source = {{0}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-find-range/double", &source); } // FLE2FindRangePayload only uses deterministic token generation. static void _test_encrypt_fle2_find_range_payload_double_precision ( _mongocrypt_tester_t *tester) { _test_rng_data_source source = {{0}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-find-range/double-precision", &source); } #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT // FLE2FindRangePayload only uses deterministic token generation. static void _test_encrypt_fle2_find_range_payload_decimal128 (_mongocrypt_tester_t *tester) { _test_rng_data_source source = {{0}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-find-range/decimal128", &source); } // FLE2FindRangePayload only uses deterministic token generation. static void _test_encrypt_fle2_find_range_payload_decimal128_precision ( _mongocrypt_tester_t *tester) { _test_rng_data_source source = {{0}}; _test_encrypt_fle2_encryption_placeholder ( tester, "fle2-find-range/decimal128-precision", &source); } #endif // MONGOCRYPT_HAVE_DECIMAL128_SUPPORT static mongocrypt_t * _crypt_with_rng (_test_rng_data_source *rng_source) { mongocrypt_t *crypt; mongocrypt_binary_t *localkey; /* localkey_data is the KEK used to encrypt the keyMaterial * in ./test/data/keys/ */ char localkey_data[MONGOCRYPT_KEY_LEN] = {0}; crypt = mongocrypt_new (); mongocrypt_setopt_log_handler (crypt, _mongocrypt_stdout_log_fn, NULL); localkey = mongocrypt_binary_new_from_data ((uint8_t *) localkey_data, sizeof localkey_data); ASSERT_OK (mongocrypt_setopt_kms_provider_local (crypt, localkey), crypt); ASSERT_OK (mongocrypt_setopt_crypto_hooks ( crypt, _std_hook_native_crypto_aes_256_cbc_encrypt, _std_hook_native_crypto_aes_256_cbc_decrypt, _test_rng_source, _std_hook_native_hmac_sha512, _std_hook_native_hmac_sha256, _error_hook_native_sha256, rng_source /* ctx */), crypt); mongocrypt_binary_destroy (localkey); ASSERT_OK (mongocrypt_init (crypt), crypt); return crypt; } typedef struct { const char *desc; _test_rng_data_source rng_data; const char *algorithm; _mongocrypt_buffer_t *user_key_id; _mongocrypt_buffer_t *index_key_id; mc_optional_int64_t contention_factor; mongocrypt_binary_t *range_opts; const char *query_type; mongocrypt_binary_t *msg; mongocrypt_binary_t *keys_to_feed[3]; // NULL terminated list. mongocrypt_binary_t *expect; const char *expect_finalize_error; const char *expect_init_error; bool is_expression; } ee_testcase; static void ee_testcase_run (ee_testcase *tc) { printf (" explicit_encryption_finalize test case: %s ... begin\n", tc->desc); extern void mc_reset_payloadId_for_testing (void); mc_reset_payloadId_for_testing (); mongocrypt_t *crypt; if (tc->rng_data.buf.len > 0) { // Use fixed data for random number generation to produce deterministic // results. crypt = _crypt_with_rng (&tc->rng_data); } else { crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); } mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); if (tc->algorithm) { ASSERT_OK (mongocrypt_ctx_setopt_algorithm (ctx, tc->algorithm, -1), ctx); } if (tc->user_key_id) { ASSERT_OK (mongocrypt_ctx_setopt_key_id ( ctx, _mongocrypt_buffer_as_binary (tc->user_key_id)), ctx); } if (tc->index_key_id) { ASSERT_OK (mongocrypt_ctx_setopt_index_key_id ( ctx, _mongocrypt_buffer_as_binary (tc->index_key_id)), ctx); } if (tc->contention_factor.set) { ASSERT_OK (mongocrypt_ctx_setopt_contention_factor ( ctx, tc->contention_factor.value), ctx); } if (tc->range_opts) { ASSERT_OK (mongocrypt_ctx_setopt_algorithm_range (ctx, tc->range_opts), ctx); } if (tc->query_type) { ASSERT_OK (mongocrypt_ctx_setopt_query_type (ctx, tc->query_type, -1), ctx); } BSON_ASSERT (tc->msg); { bool ret; if (tc->is_expression) { ret = mongocrypt_ctx_explicit_encrypt_expression_init (ctx, tc->msg); } else { ret = mongocrypt_ctx_explicit_encrypt_init (ctx, tc->msg); } if (tc->expect_init_error) { ASSERT_FAILS (ret, ctx, tc->expect_init_error); goto cleanup; } else { ASSERT_OK (ret, ctx); } } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { for (size_t i = 0; i < sizeof (tc->keys_to_feed) / sizeof (tc->keys_to_feed[0]); i++) { mongocrypt_binary_t *key_to_feed = tc->keys_to_feed[i]; if (!key_to_feed) { break; } ASSERT_OK (mongocrypt_ctx_mongo_feed (ctx, key_to_feed), ctx); } ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *got = mongocrypt_binary_new (); bool ret = mongocrypt_ctx_finalize (ctx, got); if (tc->expect_finalize_error) { ASSERT_FAILS (ret, ctx, tc->expect_finalize_error); } else { ASSERT_OK (ret, ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON (tc->expect, got); } mongocrypt_binary_destroy (got); } cleanup: printf (" explicit_encryption_finalize test case: %s ... end\n", tc->desc); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } // Test the finalized output of explicit encryption. static void _test_encrypt_fle2_explicit (_mongocrypt_tester_t *tester) { _mongocrypt_buffer_t keyABC_id; _mongocrypt_buffer_t key123_id; if (!_aes_ctr_is_supported_by_os) { printf ("Common Crypto with no CTR support detected. Skipping."); return; } _mongocrypt_buffer_copy_from_hex (&keyABC_id, "ABCDEFAB123498761234123456789012"); _mongocrypt_buffer_copy_from_hex (&key123_id, "12345678123498761234123456789012"); mongocrypt_binary_t *keyABC = TEST_FILE ("./test/data/keys/" "ABCDEFAB123498761234123456789012-local-" "document.json"); mongocrypt_binary_t *key123 = TEST_FILE ("./test/data/keys/" "12345678123498761234123456789012-local-" "document.json"); { ee_testcase tc = {0}; tc.desc = "Unindexed"; #define RNG_DATA \ "\x4d\x06\x95\x64\xf5\xa0\x5e\x9e\x35\x23\xb9\x8f\x57\x5a\xcb\x15" uint8_t rng_data[] = RNG_DATA; tc.rng_data = (_test_rng_data_source){ .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; #undef RNG_DATA tc.algorithm = MONGOCRYPT_ALGORITHM_UNINDEXED_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.msg = TEST_BSON ("{'v': 'value123'}"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_BSON ("{'v': { '$binary': { 'base64': " "'BqvN76sSNJh2EjQSNFZ4kBICTQaVZPWgXp41I7mPV1rLFTtw1tXzjc" "dSEyxpKKqujlko5TeizkB9hHQ009dVY1+fgIiDcefh+eQrm3CkhQ=='" ", 'subType': '06' } }}"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "Indexed"; #define RNG_DATA \ "\xc7\x43\xd6\x75\x76\x9e\xa7\x88\xd5\xe5\xc4\x40\xdb\x24\x0d\xf9" \ "\x4c\xd9\x64\x10\x43\x81\xe6\x61\xfa\x1f\xa0\x5c\x49\x8e\xad\x21" uint8_t rng_data[] = RNG_DATA; tc.rng_data = (_test_rng_data_source){ .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; #undef RNG_DATA tc.algorithm = MONGOCRYPT_ALGORITHM_INDEXED_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (0); tc.msg = TEST_BSON ("{'v': 'value123'}"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ("./test/data/fle2-explicit/insert-indexed.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "Indexed with non-zero ContentionFactor. Random number chosen is 0"; /* First 8 bytes are for random ContentionFactor. * Second 16 bytes are IV for 'p' field in FLE2InsertUpdatePayload * Third 16 bytes are IV for 'v' field in FLE2InsertUpdatePayload */ #define RNG_DATA \ "\x00\x00\x00\x00\x00\x00\x00\x00" \ "\xc7\x43\xd6\x75\x76\x9e\xa7\x88\xd5\xe5\xc4\x40\xdb\x24\x0d\xf9" \ "\x4c\xd9\x64\x10\x43\x81\xe6\x61\xfa\x1f\xa0\x5c\x49\x8e\xad\x21" uint8_t rng_data[] = RNG_DATA; tc.rng_data = (_test_rng_data_source){ .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; #undef RNG_DATA tc.algorithm = MONGOCRYPT_ALGORITHM_INDEXED_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (1); tc.msg = TEST_BSON ("{'v': 'value123'}"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ("./test/data/fle2-explicit/insert-indexed.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "Indexed with non-zero ContentionFactor. Random number chosen is 1"; /* First 8 bytes are for random ContentionFactor. * Second 16 bytes are IV for 'p' field in FLE2InsertUpdatePayload * Third 16 bytes are IV for 'v' field in FLE2InsertUpdatePayload */ #ifdef MONGOCRYPT_LITTLE_ENDIAN #define RNG_DATA \ "\x01\x00\x00\x00\x00\x00\x00\x00" \ "\xc7\x43\xd6\x75\x76\x9e\xa7\x88\xd5\xe5\xc4\x40\xdb\x24\x0d\xf9" \ "\x4c\xd9\x64\x10\x43\x81\xe6\x61\xfa\x1f\xa0\x5c\x49\x8e\xad\x21" #else #define RNG_DATA \ "\x00\x00\x00\x00\x00\x00\x00\x01" \ "\xc7\x43\xd6\x75\x76\x9e\xa7\x88\xd5\xe5\xc4\x40\xdb\x24\x0d\xf9" \ "\x4c\xd9\x64\x10\x43\x81\xe6\x61\xfa\x1f\xa0\x5c\x49\x8e\xad\x21" #endif /* MONGOCRYPT_LITTLE_ENDIAN */ uint8_t rng_data[] = RNG_DATA; tc.rng_data = (_test_rng_data_source){ .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; #undef RNG_DATA tc.algorithm = MONGOCRYPT_ALGORITHM_INDEXED_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (1); tc.msg = TEST_BSON ("{'v': 'value123'}"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ("./test/data/fle2-explicit/" "insert-indexed-contentionFactor1.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "omitted index_key_id defaults to using user_key_id"; #define RNG_DATA \ "\xc7\x43\xd6\x75\x76\x9e\xa7\x88\xd5\xe5\xc4\x40\xdb\x24\x0d\xf9" \ "\x4c\xd9\x64\x10\x43\x81\xe6\x61\xfa\x1f\xa0\x5c\x49\x8e\xad\x21" uint8_t rng_data[] = RNG_DATA; tc.rng_data = (_test_rng_data_source){ .buf = {.data = rng_data, .len = sizeof (rng_data) - 1u}}; #undef RNG_DATA tc.algorithm = MONGOCRYPT_ALGORITHM_INDEXED_STR; tc.user_key_id = &keyABC_id; tc.contention_factor = OPT_I64 (0); tc.msg = TEST_BSON ("{'v': 'value123'}"); tc.keys_to_feed[0] = keyABC; tc.expect = TEST_FILE ("./test/data/fle2-explicit/" "insert-indexed-same-user-and-index-key.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Indexed' with query type"; tc.algorithm = MONGOCRYPT_ALGORITHM_INDEXED_STR; tc.query_type = MONGOCRYPT_QUERY_TYPE_EQUALITY_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (0); tc.msg = TEST_BSON ("{'v': 123456}"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ("./test/data/fle2-explicit/find-indexed.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Indexed' with query type and non-zero contention factor"; tc.algorithm = MONGOCRYPT_ALGORITHM_INDEXED_STR; tc.query_type = MONGOCRYPT_QUERY_TYPE_EQUALITY_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (1); tc.msg = TEST_BSON ("{'v': 123456}"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ( "./test/data/fle2-explicit/find-indexed-contentionFactor1.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "Negative contention factor is an error on insert"; tc.algorithm = MONGOCRYPT_ALGORITHM_INDEXED_STR; tc.user_key_id = &keyABC_id; tc.contention_factor = OPT_I64 (-1); tc.msg = TEST_BSON ("{'v': 123456}"); tc.expect_init_error = "contention must be non-negative"; ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "INT64_MAX contention factor is an error on insert"; tc.algorithm = MONGOCRYPT_ALGORITHM_INDEXED_STR; tc.user_key_id = &keyABC_id; tc.contention_factor = OPT_I64 (INT64_MAX); tc.msg = TEST_BSON ("{'v': 123456}"); tc.expect_init_error = "contention must be < INT64_MAX"; ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Range' with int32"; #include "./data/fle2-insert-range-explicit/int32/RNG_DATA.h" tc.rng_data = (_test_rng_data_source){ .buf = {.data = (uint8_t *) RNG_DATA, .len = sizeof (RNG_DATA) - 1}}; #undef RNG_DATA tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (0); tc.range_opts = TEST_FILE ("./test/data/fle2-insert-range-explicit/" "int32/rangeopts.json"); tc.msg = TEST_FILE ("./test/data/fle2-insert-range-explicit/int32/" "value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ("./test/data/fle2-insert-range-explicit/int32/" "encrypted-payload.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Range' with sparsity=2 with int32"; #include "./data/fle2-insert-range-explicit/sparsity-2/RNG_DATA.h" tc.rng_data = (_test_rng_data_source){ .buf = {.data = (uint8_t *) RNG_DATA, .len = sizeof (RNG_DATA) - 1}}; #undef RNG_DATA tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (0); tc.range_opts = TEST_FILE ("./test/data/fle2-insert-range-explicit/" "sparsity-2/rangeopts.json"); tc.msg = TEST_FILE ("./test/data/fle2-insert-range-explicit/sparsity-2/" "value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ("./test/data/fle2-insert-range-explicit/sparsity-2/" "encrypted-payload.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Range' with query_type='range' with int32"; tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &keyABC_id; tc.contention_factor = OPT_I64 (4); tc.query_type = MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_STR; tc.range_opts = TEST_FILE ("./test/data/fle2-find-range-explicit/" "int32/rangeopts.json"); tc.msg = TEST_FILE ("./test/data/fle2-find-range-explicit/int32/" "value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.expect = TEST_FILE ("./test/data/fle2-find-range-explicit/int32/" "encrypted-payload.json"); tc.is_expression = true; ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "An unsupported range BSON type is an error"; tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.contention_factor = OPT_I64 (0); tc.range_opts = TEST_BSON ("{'min': 0, 'max': 1, 'sparsity': {'$numberLong': '1'}}"); tc.msg = TEST_BSON ("{'v': 'abc'}"); tc.keys_to_feed[0] = keyABC; tc.expect_finalize_error = "expected matching 'min' and value type"; ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Range' with query_type='range' with double with " "precision"; tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (0); tc.query_type = MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_STR; tc.range_opts = TEST_FILE ("./test/data/fle2-find-range-explicit/double-precision/" "rangeopts.json"); tc.msg = TEST_FILE ("./test/data/fle2-find-range-explicit/" "double-precision/value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ("./test/data/fle2-find-range-explicit/" "double-precision/encrypted-payload.json"); tc.is_expression = true; ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Range' with double precision with precision"; #include "./data/fle2-insert-range-explicit/double-precision/RNG_DATA.h" tc.rng_data = (_test_rng_data_source){ .buf = {.data = (uint8_t *) RNG_DATA, .len = sizeof (RNG_DATA) - 1}}; #undef RNG_DATA tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (0); tc.range_opts = TEST_FILE ("./test/data/fle2-insert-range-explicit/double-precision/" "rangeopts.json"); tc.msg = TEST_FILE ("./test/data/fle2-insert-range-explicit/" "double-precision/value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ("./test/data/fle2-insert-range-explicit/double-precision/" "encrypted-payload.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Range' with query_type='range' with double without " "precision"; tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (0); tc.query_type = MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_STR; tc.range_opts = TEST_FILE ("./test/data/fle2-find-range-explicit/double/" "rangeopts.json"); tc.msg = TEST_FILE ( "./test/data/fle2-find-range-explicit/double/value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ( "./test/data/fle2-find-range-explicit/double/encrypted-payload.json"); tc.is_expression = true; ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Range' with double without precision"; #include "./data/fle2-insert-range-explicit/double/RNG_DATA.h" tc.rng_data = (_test_rng_data_source){ .buf = {.data = (uint8_t *) RNG_DATA, .len = sizeof (RNG_DATA) - 1}}; #undef RNG_DATA tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.index_key_id = &key123_id; tc.contention_factor = OPT_I64 (0); tc.range_opts = TEST_FILE ("./test/data/fle2-insert-range-explicit/double/" "rangeopts.json"); tc.msg = TEST_FILE ( "./test/data/fle2-insert-range-explicit/double/value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.keys_to_feed[1] = key123; tc.expect = TEST_FILE ("./test/data/fle2-insert-range-explicit/double/" "encrypted-payload.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Range' with int32 with default min/max"; #include "./data/fle2-insert-range-explicit/int32-nominmax/RNG_DATA.h" tc.rng_data = (_test_rng_data_source){ .buf = {.data = (uint8_t *) RNG_DATA, .len = sizeof (RNG_DATA) - 1}}; #undef RNG_DATA tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.contention_factor = OPT_I64 (0); tc.range_opts = TEST_FILE ("./test/data/fle2-insert-range-explicit/" "int32-nominmax/rangeopts.json"); tc.msg = TEST_FILE ( "./test/data/fle2-insert-range-explicit/double/value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.expect = TEST_FILE ("./test/data/fle2-insert-range-explicit/int32-nominmax/" "encrypted-payload.json"); ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "algorithm='Range' and query_type='range' with int32 with " "default min/max"; tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.query_type = MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.contention_factor = OPT_I64 (0); tc.range_opts = TEST_FILE ("./test/data/fle2-find-range-explicit/" "int32-nominmax/rangeopts.json"); tc.msg = TEST_FILE ( "./test/data/fle2-find-range-explicit/double/value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.expect = TEST_FILE ("./test/data/fle2-find-range-explicit/int32-nominmax/" "encrypted-payload.json"); tc.is_expression = true; ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "min > max for insert"; tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.contention_factor = OPT_I64 (0); tc.range_opts = TEST_BSON ("{'min': 1, 'max': 0, 'sparsity': {'$numberLong': '1'}}"); tc.msg = TEST_FILE ( "./test/data/fle2-insert-range-explicit/int32/value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.expect_finalize_error = "minimum value must be less than the maximum value"; ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "min > max for find"; tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.query_type = MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.contention_factor = OPT_I64 (0); tc.range_opts = TEST_BSON ("{'min': 25, 'max': 24, 'sparsity': {'$numberLong': '1'}}"); tc.msg = TEST_FILE ( "./test/data/fle2-find-range-explicit/int32/value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.expect_finalize_error = "minimum value must be less than the maximum value"; tc.is_expression = true; ee_testcase_run (&tc); } { ee_testcase tc = {0}; tc.desc = "open interval"; tc.algorithm = MONGOCRYPT_ALGORITHM_RANGEPREVIEW_STR; tc.query_type = MONGOCRYPT_QUERY_TYPE_RANGEPREVIEW_STR; tc.user_key_id = &keyABC_id; tc.contention_factor = OPT_I64 (0); tc.range_opts = TEST_FILE ("./test/data/fle2-find-range-explicit/" "int32-openinterval/rangeopts.json"); tc.msg = TEST_FILE ("./test/data/fle2-find-range-explicit/" "int32-openinterval/value-to-encrypt.json"); tc.keys_to_feed[0] = keyABC; tc.expect = TEST_FILE ("./test/data/fle2-find-range-explicit/" "int32-openinterval/encrypted-payload.json"); tc.is_expression = true; ee_testcase_run (&tc); } _mongocrypt_buffer_cleanup (&keyABC_id); _mongocrypt_buffer_cleanup (&key123_id); } static void _test_encrypt_applies_default_state_collections (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; /* Defaults are applied */ { crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_providers ( crypt, TEST_BSON ( "{'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'bar'}}")), crypt); ASSERT_OK (mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_BSON ("{'db.coll': {'fields': []}}")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_BSON ("{'find': 'coll'}")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { const char *expect_schema = "{ 'fields': [], 'escCollection': " "'enxcol_.coll.esc', 'eccCollection': " "'enxcol_.coll.ecc', 'ecocCollection': " "'enxcol_.coll.ecoc' }"; mongocrypt_binary_t *cmd_to_mongocryptd; cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_BSON ("{'find': 'coll', 'encryptionInformation': { 'type': 1, " "'schema': { 'db.coll': %s }}}", expect_schema), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Defaults do not override. */ { crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_providers ( crypt, TEST_BSON ( "{'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'bar'}}")), crypt); ASSERT_OK ( mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_BSON ("{'db.coll': { 'fields': [], 'escCollection': 'esc', " "'eccCollection': 'ecc', 'ecocCollection': 'ecoc'}}")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_BSON ("{'find': 'coll'}")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { const char *expect_schema = "{'fields': [], 'escCollection': 'esc', " "'eccCollection': 'ecc', " "'ecocCollection': 'ecoc' }"; mongocrypt_binary_t *cmd_to_mongocryptd; cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_BSON ("{'find': 'coll', 'encryptionInformation': { 'type': 1, " "'schema': { 'db.coll': %s }}}", expect_schema), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test with some defaults. */ { crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_providers ( crypt, TEST_BSON ( "{'aws': {'accessKeyId': 'foo', 'secretAccessKey': 'bar'}}")), crypt); ASSERT_OK ( mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_BSON ("{'fields': [], 'db.coll': {'escCollection': " "'esc', 'eccCollection': 'ecc', 'fields': []}}")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_BSON ("{'find': 'coll'}")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { const char *expect_schema = "{'escCollection': 'esc', " "'eccCollection': 'ecc', 'fields': [], " "'ecocCollection': 'enxcol_.coll.ecoc' }"; mongocrypt_binary_t *cmd_to_mongocryptd; cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_BSON ("{'find': 'coll', 'encryptionInformation': { 'type': 1, " "'schema': { 'db.coll': %s }}}", expect_schema), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } } /* Test encrypting an empty 'delete' command without values to be encrypted. * Expect deleteTokens to be applied. */ static void _test_encrypt_fle2_delete (_mongocrypt_tester_t *tester) { /* Test success. */ { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-delete/success/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle2-delete/success/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/fle2-delete/success/mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "ABCDEFAB123498761234123456789012-local-document.json")), ctx); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789012-local-document.json")), ctx); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789013-local-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle2-delete/success/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test with no encrypted values. */ { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-delete/empty/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle2-delete/empty/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/fle2-delete/empty/mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789012-local-document.json")), ctx); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789013-local-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-delete/empty/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* deleteTokens are appended when bypassQueryAnalysis is true. */ { mongocrypt_t *crypt = mongocrypt_new (); /* Configure crypt. */ { char localkey_data[MONGOCRYPT_KEY_LEN] = {0}; mongocrypt_binary_t *localkey; localkey = mongocrypt_binary_new_from_data ((uint8_t *) localkey_data, sizeof localkey_data); ASSERT_OK (mongocrypt_setopt_kms_provider_local (crypt, localkey), crypt); mongocrypt_binary_destroy (localkey); mongocrypt_setopt_bypass_query_analysis (crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); } mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-delete/empty/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle2-delete/empty/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789012-local-document.json")), ctx); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789013-local-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-delete/empty/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test that deleteTokens are appended when using an * encrypted_field_config_map. */ { mongocrypt_t *crypt = mongocrypt_new (); /* Configure crypt. */ { char localkey_data[MONGOCRYPT_KEY_LEN] = {0}; mongocrypt_binary_t *localkey; localkey = mongocrypt_binary_new_from_data ((uint8_t *) localkey_data, sizeof localkey_data); ASSERT_OK (mongocrypt_setopt_kms_provider_local (crypt, localkey), crypt); mongocrypt_binary_destroy (localkey); ASSERT_OK (mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_FILE ("./test/data/fle2-delete/success/" "encrypted-field-config-map.json")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); } mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-delete/success/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/fle2-delete/success/mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "ABCDEFAB123498761234123456789012-local-document.json")), ctx); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789012-local-document.json")), ctx); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789013-local-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle2-delete/success/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test that deleteTokens are appended when using an * encrypted_field_config_map and bypass_query_analysis. */ { mongocrypt_t *crypt = mongocrypt_new (); /* Configure crypt. */ { char localkey_data[MONGOCRYPT_KEY_LEN] = {0}; mongocrypt_binary_t *localkey; localkey = mongocrypt_binary_new_from_data ((uint8_t *) localkey_data, sizeof localkey_data); ASSERT_OK (mongocrypt_setopt_kms_provider_local (crypt, localkey), crypt); mongocrypt_binary_destroy (localkey); ASSERT_OK (mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_FILE ("./test/data/fle2-delete/empty/" "encrypted-field-config-map.json")), crypt); mongocrypt_setopt_bypass_query_analysis (crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); } mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-delete/empty/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789012-local-document.json")), ctx); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789013-local-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-delete/empty/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } } /* Test behavior introduced in MONGOCRYPT-423: "encryptionInformation" is * omitted when no values are encrypted for eligible commands.*/ static void _test_encrypt_fle2_omits_encryptionInformation (_mongocrypt_tester_t *tester) { /* 'find' does not include 'encryptionInformation' if no fields are * encrypted. */ { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx; ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_BSON ("{'find': 'coll'}")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_BSON ("{'name': 'coll', 'options': " "{'encryptedFields': {'fields': []}}}")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } /* Check that command to mongocryptd includes "encryptionInformation". */ ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/find-with-encryptionInformation.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *cmd_to_mongod; cmd_to_mongod = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, cmd_to_mongod), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON (TEST_BSON ("{'find': 'coll'}"), cmd_to_mongod); mongocrypt_binary_destroy (cmd_to_mongod); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* 'find' includes encryptionInformation if the initial command includes an * explicitly encrypted payload. */ { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx; ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-find-explicit/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_BSON ("{'name': 'coll', 'options': " "{'encryptedFields': {'fields': []}}}")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } /* Check that command to mongocryptd includes "encryptionInformation". */ ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle2-find-explicit/cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *cmd_to_mongod; cmd_to_mongod = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, cmd_to_mongod), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-find-explicit/cmd-to-mongod.json"), cmd_to_mongod); mongocrypt_binary_destroy (cmd_to_mongod); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } } static void _test_encrypt_fle2_explain_with_mongocryptd (_mongocrypt_tester_t *tester) { /* Test with an encrypted value. Otherwise 'encryptionInformation' is not * appended. */ { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK ( mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-explain/with-mongocryptd/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/fle2-explain/with-mongocryptd/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-explain/with-mongocryptd/" "cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle2-explain/with-mongocryptd/" "mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "ABCDEFAB123498761234123456789012-local-document.json")), ctx); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789012-local-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-explain/with-mongocryptd/" "encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } } static void _test_encrypt_fle2_explain_with_csfle (_mongocrypt_tester_t *tester) { if (!TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB) { fputs ("No 'real' csfle library is available. The " "_test_encrypt_fle2_explain_with_csfle test is a no-op.", stderr); return; } /* Test with an encrypted value. Otherwise 'encryptionInformation' is not * appended. */ { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt ( TESTER_MONGOCRYPT_WITH_CRYPT_SHARED_LIB); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-explain/with-csfle/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle2-explain/with-csfle/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/keys/" "12345678123498761234123456789012-local-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-explain/with-csfle/" "encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } } static void _test_encrypt_fle1_explain_with_mongocryptd (_mongocrypt_tester_t *tester) { { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK ( mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle1-explain/with-mongocryptd/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ( "./test/data/fle1-explain/with-mongocryptd/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle1-explain/with-mongocryptd/" "cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-explain/with-mongocryptd/" "mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle1-explain/with-mongocryptd/" "encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } } static void _test_encrypt_fle1_explain_with_csfle (_mongocrypt_tester_t *tester) { if (!TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB) { fputs ("No 'real' csfle library is available. The " "_test_encrypt_fle1_explain_with_csfle test is a no-op.", stderr); return; } { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt ( TESTER_MONGOCRYPT_WITH_CRYPT_SHARED_LIB); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle1-explain/with-csfle/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-explain/with-csfle/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle1-explain/with-csfle/" "encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } } // Test that an input command with $db preserves $db in the output. static void _test_dollardb_preserved (_mongocrypt_tester_t *tester) { /* Test with an encrypted value. */ mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK ( mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/dollardb/preserved/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/dollardb/preserved/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/dollardb/preserved/" "cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK ( mongocrypt_ctx_mongo_feed (ctx, TEST_FILE ("./test/data/dollardb/preserved/" "mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/keys/" "ABCDEFAB123498761234123456789012-local-document.json")), ctx); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/keys/" "12345678123498761234123456789012-local-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/dollardb/preserved/" "encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } // Test that an input command with $db preserves $db in the output, when no // values are encrypted. static void _test_dollardb_preserved_empty (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/dollardb/preserved_empty/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/dollardb/preserved_empty/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/dollardb/preserved_empty/" "cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/dollardb/preserved_empty/" "mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/dollardb/preserved_empty/" "encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } // Test that an input command with no $db does not include $db in the output. static void _test_dollardb_omitted (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK ( mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/dollardb/omitted/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/dollardb/omitted/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/dollardb/omitted/" "cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK ( mongocrypt_ctx_mongo_feed (ctx, TEST_FILE ("./test/data/dollardb/omitted/" "mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/keys/" "ABCDEFAB123498761234123456789012-local-document.json")), ctx); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/keys/" "12345678123498761234123456789012-local-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/dollardb/omitted/" "encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } // Test that an input command with $db does includes $db in the output for FLE1. static void _test_dollardb_preserved_fle1 (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/dollardb/preserved_fle1/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/dollardb/preserved_fle1/collinfo.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/dollardb/preserved_fle1/" "cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/dollardb/preserved_fle1/" "mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/keys/" "12345678123498761234123456789012-local-document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/dollardb/preserved_fle1/" "encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_fle1_create_without_schema (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle1-create/without-schema/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle1-create/without-schema/" "ismaster-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-create/without-schema/" "mongocryptd-ismaster.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle1-create/without-schema/cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-create/without-schema/" "mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle1-create/without-schema/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test encrypting a "create" command with a schema from the schema map. */ static void _test_fle1_create_with_schema (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_provider_aws (crypt, "example", -1, "example", -1), crypt); ASSERT_OK ( mongocrypt_setopt_schema_map ( crypt, TEST_FILE ("./test/data/fle1-create/with-schema/schema-map.json")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle1-create/with-schema/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle1-create/with-schema/" "ismaster-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-create/with-schema/" "mongocryptd-ismaster.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle1-create/with-schema/cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-create/with-schema/" "mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle1-create/with-schema/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test encrypting a "create" command with a schema included in the "create" * command. This is a regression test for MONGOCRYPT-436. */ static void _test_fle1_create_with_cmd_schema (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK ( mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle1-create/with-cmd-schema/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle1-create/with-cmd-schema/" "ismaster-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-create/with-cmd-schema/" "mongocryptd-ismaster.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle1-create/with-cmd-schema/cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-create/with-cmd-schema/" "mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle1-create/with-cmd-schema/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Test encrypting the "create" command with mongocryptd version < 6.0.0. * Expect the "create" command not to be sent to mongocryptd. */ static void _test_fle1_create_old_mongocryptd (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK ( mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle1-create/old-mongocryptd/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle1-create/old-mongocryptd/" "ismaster-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-create/old-mongocryptd/" "mongocryptd-ismaster.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle1-create/old-mongocryptd/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_fle1_create_with_csfle (_mongocrypt_tester_t *tester) { if (!TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB) { fputs ("No 'real' csfle library is available. The " "_test_fle1_create_with_csfle test is a no-op.", stderr); return; } mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_WITH_CRYPT_SHARED_LIB); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle1-create/with-schema/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ( "./test/data/fle1-create/with-schema/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } static void _test_fle2_create (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_provider_aws (crypt, "example", -1, "example", -1), crypt); ASSERT_OK ( mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_FILE ("./test/data/fle2-create/encrypted-field-config-map.json")), crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-create/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle1-create/without-schema/" "ismaster-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-create/without-schema/" "mongocryptd-ismaster.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-create/cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle2-create/mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-create/encrypted-payload.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* Regression test for MONGOCRYPT-435 */ static void _test_fle2_create_bypass_query_analysis (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = mongocrypt_new (); ASSERT_OK ( mongocrypt_setopt_kms_provider_aws (crypt, "example", -1, "example", -1), crypt); ASSERT_OK ( mongocrypt_setopt_encrypted_field_config_map ( crypt, TEST_FILE ("./test/data/fle2-create/encrypted-field-config-map.json")), crypt); mongocrypt_setopt_bypass_query_analysis (crypt); ASSERT_OK (mongocrypt_init (crypt), crypt); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle2-create/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *out = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_finalize (ctx, out), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle2-create/cmd.json"), out); mongocrypt_binary_destroy (out); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } // Test the error message returned on macOS versions that do not support AES-CTR // mode. This tests behavior changed in MONGOCRYPT-440. static void _test_encrypt_macos_no_ctr (_mongocrypt_tester_t *tester) { _mongocrypt_buffer_t key_id; if (_aes_ctr_is_supported_by_os) { printf ("Common Crypto with CTR support detected. Skipping."); return; } _mongocrypt_buffer_copy_from_hex (&key_id, "ABCDEFAB123498761234123456789012"); mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK (mongocrypt_ctx_setopt_algorithm ( ctx, MONGOCRYPT_ALGORITHM_UNINDEXED_STR, -1), ctx); ASSERT_OK (mongocrypt_ctx_setopt_key_id ( ctx, _mongocrypt_buffer_as_binary (&key_id)), ctx); ASSERT_OK (mongocrypt_ctx_explicit_encrypt_init ( ctx, TEST_BSON ("{'v': 'value123'}")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK (mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/keys/" "ABCDEFAB123498761234123456789012-local-" "document.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_READY); { mongocrypt_binary_t *got = mongocrypt_binary_new (); ASSERT_FAILS (mongocrypt_ctx_finalize (ctx, got), ctx, "CTR mode is only supported on macOS 10.15+"); mongocrypt_binary_destroy (got); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* If collMod contains a $jsonSchema, expect the same $jsonSchema to be used in * the command to mongocryptd. This is a regression test for MONGOCRYPT-463. */ static void _test_fle1_collmod_with_jsonSchema (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK ( mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_FILE ("./test/data/fle1-collMod/cmd.json")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_MARKINGS); { mongocrypt_binary_t *cmd_to_mongocryptd = mongocrypt_binary_new (); ASSERT_OK (mongocrypt_ctx_mongo_op (ctx, cmd_to_mongocryptd), ctx); ASSERT_MONGOCRYPT_BINARY_EQUAL_BSON ( TEST_FILE ("./test/data/fle1-collMod/cmd-to-mongocryptd.json"), cmd_to_mongocryptd); mongocrypt_binary_destroy (cmd_to_mongocryptd); ASSERT_OK ( mongocrypt_ctx_mongo_feed ( ctx, TEST_FILE ("./test/data/fle1-collMod/mongocryptd-reply.json")), ctx); ASSERT_OK (mongocrypt_ctx_mongo_done (ctx), ctx); } mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } /* If collMod does not contain a $jsonSchema, expect a schema to be requested. */ static void _test_fle1_collmod_without_jsonSchema (_mongocrypt_tester_t *tester) { mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt (TESTER_MONGOCRYPT_DEFAULT); mongocrypt_ctx_t *ctx = mongocrypt_ctx_new (crypt); ASSERT_OK ( mongocrypt_ctx_encrypt_init ( ctx, "db", -1, TEST_BSON ("{'collMod': 'encryptedCollection'}")), ctx); ASSERT_STATE_EQUAL (mongocrypt_ctx_state (ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); mongocrypt_ctx_destroy (ctx); mongocrypt_destroy (crypt); } void _mongocrypt_tester_install_ctx_encrypt (_mongocrypt_tester_t *tester) { INSTALL_TEST (_test_explicit_encrypt_init); INSTALL_TEST (_test_encrypt_init); INSTALL_TEST (_test_encrypt_need_collinfo); INSTALL_TEST (_test_encrypt_need_markings); INSTALL_TEST (_test_encrypt_csfle_no_needs_markings); INSTALL_TEST (_test_encrypt_need_keys); INSTALL_TEST (_test_encrypt_ready); INSTALL_TEST (_test_key_missing_region); INSTALL_TEST (_test_view); INSTALL_TEST (_test_local_schema); INSTALL_TEST (_test_encrypt_caches_collinfo); INSTALL_TEST (_test_encrypt_caches_keys); INSTALL_TEST (_test_encrypt_caches_keys_by_alt_name); INSTALL_TEST (_test_encrypt_random); INSTALL_TEST (_test_encrypt_is_remote_schema); INSTALL_TEST (_test_encrypt_init_each_cmd); INSTALL_TEST (_test_encrypt_invalid_siblings); INSTALL_TEST (_test_encrypt_dupe_jsonschema); INSTALL_TEST (_test_encrypting_with_explicit_encryption); INSTALL_TEST (_test_explicit_encryption); INSTALL_TEST (_test_encrypt_empty_aws); INSTALL_TEST (_test_encrypt_custom_endpoint); INSTALL_TEST (_test_encrypt_with_aws_session_token); INSTALL_TEST (_test_encrypt_caches_empty_collinfo); INSTALL_TEST (_test_encrypt_caches_collinfo_without_jsonschema); INSTALL_TEST (_test_encrypt_per_ctx_credentials); INSTALL_TEST (_test_encrypt_per_ctx_credentials_given_empty); INSTALL_TEST (_test_encrypt_per_ctx_credentials_local); INSTALL_TEST (_test_encrypt_with_encrypted_field_config_map); INSTALL_TEST (_test_encrypt_with_encrypted_field_config_map_bypassed); INSTALL_TEST (_test_encrypt_no_schema); INSTALL_TEST (_test_encrypt_remote_encryptedfields); INSTALL_TEST (_test_encrypt_with_bypassqueryanalysis); INSTALL_TEST (_test_FLE2EncryptionPlaceholder_parse); INSTALL_TEST (_test_encrypt_fle2_insert_payload); INSTALL_TEST (_test_encrypt_fle2_find_payload); INSTALL_TEST (_test_encrypt_fle2_unindexed_encrypted_payload); INSTALL_TEST (_test_encrypt_fle2_explicit); INSTALL_TEST (_test_encrypt_applies_default_state_collections); INSTALL_TEST (_test_encrypt_fle2_delete); INSTALL_TEST (_test_encrypt_fle2_omits_encryptionInformation); INSTALL_TEST (_test_encrypt_fle2_explain_with_mongocryptd); INSTALL_TEST (_test_encrypt_fle2_explain_with_csfle); INSTALL_TEST (_test_encrypt_fle1_explain_with_mongocryptd); INSTALL_TEST (_test_encrypt_fle1_explain_with_csfle); INSTALL_TEST (_test_dollardb_preserved); INSTALL_TEST (_test_dollardb_preserved_empty); INSTALL_TEST (_test_dollardb_omitted); INSTALL_TEST (_test_dollardb_preserved_fle1); INSTALL_TEST (_test_fle1_create_without_schema); INSTALL_TEST (_test_fle1_create_with_schema); INSTALL_TEST (_test_fle1_create_with_cmd_schema); INSTALL_TEST (_test_fle1_create_old_mongocryptd); INSTALL_TEST (_test_fle1_create_with_csfle); INSTALL_TEST (_test_fle2_create); INSTALL_TEST (_test_fle2_create_bypass_query_analysis); INSTALL_TEST (_test_encrypt_macos_no_ctr); INSTALL_TEST (_test_fle1_collmod_with_jsonSchema); INSTALL_TEST (_test_fle1_collmod_without_jsonSchema); INSTALL_TEST (_test_FLE2EncryptionPlaceholder_range_parse); INSTALL_TEST (_test_encrypt_fle2_insert_range_payload_int32); INSTALL_TEST (_test_encrypt_fle2_insert_range_payload_int64); INSTALL_TEST (_test_encrypt_fle2_insert_range_payload_date); INSTALL_TEST (_test_encrypt_fle2_insert_range_payload_double); INSTALL_TEST (_test_encrypt_fle2_insert_range_payload_double_precision); #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT INSTALL_TEST (_test_encrypt_fle2_insert_range_payload_decimal128); INSTALL_TEST (_test_encrypt_fle2_insert_range_payload_decimal128_precision); #endif INSTALL_TEST (_test_encrypt_fle2_find_range_payload_int32); INSTALL_TEST (_test_encrypt_fle2_find_range_payload_int64); INSTALL_TEST (_test_encrypt_fle2_find_range_payload_date); INSTALL_TEST (_test_encrypt_fle2_find_range_payload_double); INSTALL_TEST (_test_encrypt_fle2_find_range_payload_double_precision); #if MONGOCRYPT_HAVE_DECIMAL128_SUPPORT INSTALL_TEST (_test_encrypt_fle2_find_range_payload_decimal128); INSTALL_TEST (_test_encrypt_fle2_find_range_payload_decimal128_precision); #endif }