From bc6780d133ec2564afec08907dff59f2e7d5483e Mon Sep 17 00:00:00 2001 From: Kevin Albertson Date: Wed, 26 Jun 2024 09:33:14 -0400 Subject: [PATCH 1/3] add failing test --- test/data/compact/no-range/cmd.json | 1 + test/data/compact/no-range/collinfo.json | 49 ++++++++++++++++ .../no-range/encrypted-field-config-map.json | 47 +++++++++++++++ .../compact/no-range/encrypted-payload.json | 23 ++++++++ test/test-mongocrypt-compact.c | 58 +++++++++++++++++++ 5 files changed, 178 insertions(+) create mode 100644 test/data/compact/no-range/cmd.json create mode 100644 test/data/compact/no-range/collinfo.json create mode 100644 test/data/compact/no-range/encrypted-field-config-map.json create mode 100644 test/data/compact/no-range/encrypted-payload.json diff --git a/test/data/compact/no-range/cmd.json b/test/data/compact/no-range/cmd.json new file mode 100644 index 000000000..ddf4cfde1 --- /dev/null +++ b/test/data/compact/no-range/cmd.json @@ -0,0 +1 @@ +{ "compactStructuredEncryptionData": "test" } diff --git a/test/data/compact/no-range/collinfo.json b/test/data/compact/no-range/collinfo.json new file mode 100644 index 000000000..262768aa1 --- /dev/null +++ b/test/data/compact/no-range/collinfo.json @@ -0,0 +1,49 @@ +{ + "options": { + "encryptedFields": { + "escCollection": "esc", + "eccCollection": "ecc", + "ecocCollection": "ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encrypted", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": 0 + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "nested.encrypted", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": 0 + } + }, + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEw==", + "subType": "04" + } + }, + "path": "nested.notindexed", + "bsonType": "string" + } + ] + } + } +} diff --git a/test/data/compact/no-range/encrypted-field-config-map.json b/test/data/compact/no-range/encrypted-field-config-map.json new file mode 100644 index 000000000..f183f7d30 --- /dev/null +++ b/test/data/compact/no-range/encrypted-field-config-map.json @@ -0,0 +1,47 @@ +{ + "db.test": { + "escCollection": "esc", + "eccCollection": "ecc", + "ecocCollection": "ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encrypted", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": 0 + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "nested.encrypted", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": 0 + } + }, + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEw==", + "subType": "04" + } + }, + "path": "nested.notindexed", + "bsonType": "string" + } + ] + } +} diff --git a/test/data/compact/no-range/encrypted-payload.json b/test/data/compact/no-range/encrypted-payload.json new file mode 100644 index 000000000..f861ac775 --- /dev/null +++ b/test/data/compact/no-range/encrypted-payload.json @@ -0,0 +1,23 @@ +{ + "compactStructuredEncryptionData": "test", + "compactionTokens": { + "nested.notindexed": { + "$binary": { + "base64": "27J6DZqcjkRzZ3lWEsxH7CsQHr4CZirrGmuPS8ZkRO0=", + "subType": "00" + } + }, + "nested.encrypted": { + "$binary": { + "base64": "SWO8WEoZ2r2Kx/muQKb7+COizy85nIIUFiHh4K9kcvA=", + "subType": "00" + } + }, + "encrypted": { + "$binary": { + "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=", + "subType": "00" + } + } + } +} diff --git a/test/test-mongocrypt-compact.c b/test/test-mongocrypt-compact.c index 6f19a8ce6..255f709ce 100644 --- a/test/test-mongocrypt-compact.c +++ b/test/test-mongocrypt-compact.c @@ -81,6 +81,64 @@ static void _test_compact_success(_mongocrypt_tester_t *tester) { mongocrypt_destroy(crypt); } } + + // Test `compactStructuredEncryptionData` without range fields omits encryptionInformation. + // This is a regression test for MONGOCRYPT-699. + for (int use_range_v2 = 0; use_range_v2 <= 1; use_range_v2++) { + datapath[nullb] = 0; + strcat(datapath, "no-range/"); + strcpy(cmdfile, datapath); + strcat(cmdfile, "cmd.json"); + strcpy(collfile, datapath); + strcat(collfile, "collinfo.json"); + strcpy(payloadfile, datapath); + strcat(payloadfile, "encrypted-payload.json"); // Expect same result regardless of range v2. + + mongocrypt_t *crypt; + mongocrypt_ctx_t *ctx; + + crypt = + _mongocrypt_tester_mongocrypt(use_range_v2 ? TESTER_MONGOCRYPT_WITH_RANGE_V2 : TESTER_MONGOCRYPT_DEFAULT); + ctx = mongocrypt_ctx_new(crypt); + + ASSERT_OK(mongocrypt_ctx_encrypt_init(ctx, "db", -1, TEST_FILE(cmdfile)), ctx); + + ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_NEED_MONGO_COLLINFO); + { + ASSERT_OK(mongocrypt_ctx_mongo_feed(ctx, TEST_FILE(collfile)), 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/" + "ABCDEFAB123498761234123456789012-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(payloadfile), out); + mongocrypt_binary_destroy(out); + } + + ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_DONE); + + mongocrypt_ctx_destroy(ctx); + mongocrypt_destroy(crypt); + } } static void _test_compact_nonlocal_kms(_mongocrypt_tester_t *tester) { From 169cbaac192e65e9b9330d6ffc67eab03e0added Mon Sep 17 00:00:00 2001 From: Kevin Albertson Date: Thu, 27 Jun 2024 10:31:04 -0400 Subject: [PATCH 2/3] MONGOCRYPT-699 omit `encryptionInformation` if range fields not present --- src/mongocrypt-ctx-encrypt.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/mongocrypt-ctx-encrypt.c b/src/mongocrypt-ctx-encrypt.c index 0ca1aa9a7..dbc080439 100644 --- a/src/mongocrypt-ctx-encrypt.c +++ b/src/mongocrypt-ctx-encrypt.c @@ -1370,6 +1370,7 @@ typedef struct { static moe_result must_omit_encryptionInformation(const char *command_name, const bson_t *command, bool use_range_v2, + const mc_EncryptedFieldConfig_t *efc, mongocrypt_status_t *status) { // eligible_commands may omit encryptionInformation if the command does not // contain payloads requiring encryption. @@ -1382,10 +1383,23 @@ static moe_result must_omit_encryptionInformation(const char *command_name, BSON_ASSERT_PARAM(command_name); BSON_ASSERT_PARAM(command); + BSON_ASSERT_PARAM(efc); - // Before range v2, compact is a prohibited command. After, it must have encryption information. - if (!use_range_v2 && 0 == strcmp("compactStructuredEncryptionData", command_name)) { - return (moe_result){.ok = true, .must_omit = true}; + if (0 == strcmp("compactStructuredEncryptionData", command_name)) { + // `compactStructuredEncryptionData` is a special case: + // - Server 7.0 prohibits `encryptionInformation`. + // - Server 8.0 requires `encryptionInformation` if "range" fields are referenced. Otherwise ignores. + // Only send `encryptionInformation` if "range" fields are present to support both server versions. + bool uses_range_fields = false; + if (use_range_v2) { + for (const mc_EncryptedField_t *ef = efc->fields; ef != NULL; ef = ef->next) { + if (ef->supported_queries & SUPPORTS_RANGE_QUERIES) { + uses_range_fields = true; + break; + } + } + } + return (moe_result){.ok = true, .must_omit = !uses_range_fields}; } for (i = 0; i < sizeof(prohibited_commands) / sizeof(prohibited_commands[0]); i++) { @@ -1727,8 +1741,11 @@ static bool _fle2_finalize(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out) { } } - moe_result result = - must_omit_encryptionInformation(command_name, &converted, ctx->crypt->opts.use_range_v2, ctx->status); + moe_result result = must_omit_encryptionInformation(command_name, + &converted, + ctx->crypt->opts.use_range_v2, + &ectx->efc, + ctx->status); if (!result.ok) { bson_destroy(&converted); bson_destroy(deleteTokens); From 55feab64e3162389fff158027113a8a98e9c08d1 Mon Sep 17 00:00:00 2001 From: Kevin Albertson Date: Thu, 27 Jun 2024 15:57:07 -0400 Subject: [PATCH 3/3] update payload for python test --- .../compact/success/encrypted-payload.json | 50 ------------------- 1 file changed, 50 deletions(-) diff --git a/bindings/python/test/data/compact/success/encrypted-payload.json b/bindings/python/test/data/compact/success/encrypted-payload.json index 4e837d28f..7eb7ea7cb 100644 --- a/bindings/python/test/data/compact/success/encrypted-payload.json +++ b/bindings/python/test/data/compact/success/encrypted-payload.json @@ -1,55 +1,5 @@ { "compactStructuredEncryptionData": "test", - "encryptionInformation": { - "type": 1, - "schema": { - "db.test": { - "escCollection": "esc", - "eccCollection": "ecc", - "ecocCollection": "ecoc", - "fields": [ - { - "keyId": { - "$binary": { - "base64": "EjRWeBI0mHYSNBI0VniQEg==", - "subType": "04" - } - }, - "path": "encrypted", - "bsonType": "string", - "queries": { - "queryType": "equality", - "contention": 0 - } - }, - { - "keyId": { - "$binary": { - "base64": "q83vqxI0mHYSNBI0VniQEg==", - "subType": "04" - } - }, - "path": "nested.encrypted", - "bsonType": "string", - "queries": { - "queryType": "equality", - "contention": 0 - } - }, - { - "keyId": { - "$binary": { - "base64": "EjRWeBI0mHYSNBI0VniQEw==", - "subType": "04" - } - }, - "path": "nested.notindexed", - "bsonType": "string" - } - ] - } - } - }, "compactionTokens": { "nested.notindexed": { "$binary": {