File: test-mongocrypt-csfle-lib.c

package info (click to toggle)
libmongocrypt 1.17.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 12,572 kB
  • sloc: ansic: 70,067; python: 4,547; cpp: 615; sh: 460; makefile: 44; awk: 8
file content (215 lines) | stat: -rw-r--r-- 10,464 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#include "mongocrypt.h"

#include "mongocrypt-util-private.h"
#include "test-mongocrypt.h"

static mongocrypt_t *get_test_mongocrypt(_mongocrypt_tester_t *tester) {
    mongocrypt_t *crypt = mongocrypt_new();
    mongocrypt_setopt_log_handler(crypt, _mongocrypt_stdout_log_fn, NULL);
    mongocrypt_binary_t *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);
    return crypt;
}

static void _test_csfle_no_paths(_mongocrypt_tester_t *tester) {
    /// Test that mongocrypt_init succeeds if we have no search path
    mongocrypt_t *const crypt = get_test_mongocrypt(tester);
    ASSERT_OK(_mongocrypt_init_for_test(crypt), crypt);
    // No csfle was loaded:
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version_string(crypt, NULL) == NULL);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version(crypt) == 0);
    mongocrypt_destroy(crypt);
}

static void _test_csfle_not_found(_mongocrypt_tester_t *tester) {
    /// Test that mongocrypt_init succeeds even if the csfle library was not
    /// found but a search path was specified
    mongocrypt_t *const crypt = get_test_mongocrypt(tester);
    mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt, "/no-such-directory");
    ASSERT_OK(_mongocrypt_init_for_test(crypt), crypt);
    // No csfle was loaded:
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version_string(crypt, NULL) == NULL);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version(crypt) == 0);
    mongocrypt_destroy(crypt);
}

static void _test_csfle_load(_mongocrypt_tester_t *tester) {
    mongocrypt_t *const crypt = get_test_mongocrypt(tester);
    mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt, "no-such-directory");
    mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt, "$ORIGIN");
    mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt, "another-no-such-dir");
    ASSERT_OK(_mongocrypt_init_for_test(crypt), crypt);
    // csfle WAS loaded:
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version_string(crypt, NULL) != NULL);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version(crypt) != 0);
    mstr_view version = mstrv_view_cstr(mongocrypt_crypt_shared_lib_version_string(crypt, NULL));
    if (TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB) {
        MSTR_ASSERT(true, version, starts_with, mstrv_lit("mongo_crypt_v1-"));
    } else {
        MSTR_ASSERT(true, version, eq, mstrv_lit("stubbed-crypt_shared"));
    }
    mongocrypt_destroy(crypt);
}

static void _test_csfle_load_twice(_mongocrypt_tester_t *tester) {
    mongocrypt_t *const crypt1 = get_test_mongocrypt(tester);
    mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt1, "$ORIGIN");
    ASSERT_OK(_mongocrypt_init_for_test(crypt1), crypt1);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version_string(crypt1, NULL) != NULL);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version(crypt1) != 0);

    // Make another one:
    mongocrypt_t *const crypt2 = get_test_mongocrypt(tester);
    mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt2, "$ORIGIN");
    ASSERT_OK(_mongocrypt_init_for_test(crypt2), crypt2);
    // csfle was loaded again:
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version_string(crypt2, NULL) != NULL);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version(crypt2) != 0);

    mstr_view version = mstrv_view_cstr(mongocrypt_crypt_shared_lib_version_string(crypt1, NULL));
    if (TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB) {
        MSTR_ASSERT(true, version, starts_with, mstrv_lit("mongo_crypt_v1-"));
    } else {
        MSTR_ASSERT(true, version, eq, mstrv_lit("stubbed-crypt_shared"));
    }

    version = mstrv_view_cstr(mongocrypt_crypt_shared_lib_version_string(crypt2, NULL));
    if (TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB) {
        MSTR_ASSERT(true, version, starts_with, mstrv_lit("mongo_crypt_v1-"));
    } else {
        MSTR_ASSERT(true, version, eq, mstrv_lit("stubbed-crypt_shared"));
    }

    mongocrypt_destroy(crypt1);
    mongocrypt_destroy(crypt2);
}

static void _test_csfle_load_twice_fail(_mongocrypt_tester_t *tester) {
    mongocrypt_t *const crypt1 = get_test_mongocrypt(tester);
    mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt1, "$ORIGIN");
    ASSERT_OK(_mongocrypt_init_for_test(crypt1), crypt1);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version_string(crypt1, NULL) != NULL);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version(crypt1) != 0);

    // Make another one, but finding a different dynamic library:
    mongocrypt_t *const crypt2 = get_test_mongocrypt(tester);
    mongocrypt_setopt_set_crypt_shared_lib_path_override(crypt2, "$ORIGIN/stubbed-crypt_shared-2.dll");
    // Loading a second different library is an error:
    ASSERT_FAILS(_mongocrypt_init_for_test(crypt2), crypt2, "attempted to load a second crypt_shared library");

    mstr_view version = mstrv_view_cstr(mongocrypt_crypt_shared_lib_version_string(crypt1, NULL));
    if (TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB) {
        MSTR_ASSERT(true, version, starts_with, mstrv_lit("mongo_crypt_v1-"));
    } else {
        MSTR_ASSERT(true, version, eq, mstrv_lit("stubbed-crypt_shared"));
    }

    mongocrypt_destroy(crypt1);
    mongocrypt_destroy(crypt2);
}

static void _test_csfle_path_override_okay(_mongocrypt_tester_t *tester) {
    mongocrypt_t *const crypt = get_test_mongocrypt(tester);
    // Set to the absolute path to the DLL we use for testing:
    mongocrypt_setopt_set_crypt_shared_lib_path_override(crypt, "$ORIGIN/mongo_crypt_v1" MCR_DLL_SUFFIX);
    ASSERT_OK(_mongocrypt_init_for_test(crypt), crypt);
    // csfle WAS loaded:
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version_string(crypt, NULL) != NULL);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version(crypt) != 0);
    mstr_view version = mstrv_view_cstr(mongocrypt_crypt_shared_lib_version_string(crypt, NULL));
    if (TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB) {
        MSTR_ASSERT(true, version, starts_with, mstrv_lit("mongo_crypt_v1-"));
    } else {
        MSTR_ASSERT(true, version, eq, mstrv_lit("stubbed-crypt_shared"));
    }
    mongocrypt_destroy(crypt);
}

static void _test_csfle_path_override_fail(_mongocrypt_tester_t *tester) {
    mongocrypt_t *const crypt = get_test_mongocrypt(tester);
    // Set to the absolute path to a file that does not exist
    mongocrypt_setopt_set_crypt_shared_lib_path_override(crypt,
                                                         "/no-such-file-or-directory/mongo_crypt_v1" MCR_DLL_SUFFIX);
    // This *would* succeed, but we don't use the search paths if an absolute
    // override was specified:
    mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt, "$ORIGIN");
    ASSERT_FAILS(_mongocrypt_init_for_test(crypt), crypt, "but we failed to open a dynamic library at that location");
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version_string(crypt, NULL) == NULL);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version(crypt) == 0);
    mongocrypt_destroy(crypt);
}

static void _test_cur_exe_path(_mongocrypt_tester_t *tester) {
    current_module_result self = current_module_path();
    BSON_ASSERT(self.error == 0);
    BSON_ASSERT(self.path.raw.len != 0);
    mstr_free(self.path);
}

static void _test_csfle_not_loaded_with_bypassqueryanalysis(_mongocrypt_tester_t *tester) {
    mongocrypt_t *const crypt = get_test_mongocrypt(tester);
    mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt, "$ORIGIN");
    mongocrypt_setopt_bypass_query_analysis(crypt);
    ASSERT_OK(_mongocrypt_init_for_test(crypt), crypt);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version_string(crypt, NULL) == NULL);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version(crypt) == 0);

    mongocrypt_destroy(crypt);
}

// _test_override_error_includes_reason test changes of MONGOCRYPT-576: the error message from mcr_dll_open is
// propagated.
static void _test_override_error_includes_reason(_mongocrypt_tester_t *tester) {
    mongocrypt_t *crypt = get_test_mongocrypt(tester);
    // Set an incorrect override path.
    mongocrypt_setopt_set_crypt_shared_lib_path_override(crypt, "invalid_path_to_crypt_shared.so");
    ASSERT_FAILS(_mongocrypt_init_for_test(crypt), crypt, "Error while opening candidate");
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version_string(crypt, NULL) == NULL);
    BSON_ASSERT(mongocrypt_crypt_shared_lib_version(crypt) == 0);
    mongocrypt_destroy(crypt);
}

static void _test_lookup_version_check(_mongocrypt_tester_t *tester) {
    if (!TEST_MONGOCRYPT_HAVE_REAL_CRYPT_SHARED_LIB) {
        TEST_STDERR_PRINTF("No 'real' csfle library is available. The %s test is a no-op.\n", BSON_FUNC);
        return;
    }

#define CRYPT_SHARED_8_1 0x0008000100000000ull
    mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt(TESTER_MONGOCRYPT_WITH_CRYPT_SHARED_LIB);
    uint64_t version = crypt->csfle.get_version();
    mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
    mongocrypt_binary_t *cmd = TEST_FILE("./test/data/lookup/csfle/cmd.json");
    if (version >= CRYPT_SHARED_8_1) {
        ASSERT_OK(mongocrypt_ctx_encrypt_init(ctx, "db", -1, cmd), ctx);
    } else {
        ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, "db", -1, cmd), ctx, "Upgrade crypt_shared");
    }
    mongocrypt_ctx_destroy(ctx);
    mongocrypt_destroy(crypt);
}

static void _test_loading_libmongocrypt_fails(_mongocrypt_tester_t *tester) {
    mongocrypt_t *const crypt = get_test_mongocrypt(tester);
    const char *path_to_libmongocrypt = TEST_MONGOCRYPT_MONGOCRYPT_SHARED_PATH;
    mongocrypt_setopt_set_crypt_shared_lib_path_override(crypt, path_to_libmongocrypt);
    bool ok = mongocrypt_init(crypt);
    ASSERT_FAILS(ok, crypt, "detected libmongocrypt");
    mongocrypt_destroy(crypt);
}

void _mongocrypt_tester_install_csfle_lib(_mongocrypt_tester_t *tester) {
    INSTALL_TEST(_test_csfle_no_paths);
    INSTALL_TEST(_test_csfle_not_found);
    INSTALL_TEST(_test_csfle_load);
    INSTALL_TEST(_test_csfle_load_twice);
    INSTALL_TEST(_test_csfle_load_twice_fail);
    INSTALL_TEST(_test_csfle_path_override_okay);
    INSTALL_TEST(_test_csfle_path_override_fail);
    INSTALL_TEST(_test_cur_exe_path);
    INSTALL_TEST(_test_csfle_not_loaded_with_bypassqueryanalysis);
    INSTALL_TEST(_test_override_error_includes_reason);
    INSTALL_TEST(_test_lookup_version_check);
    INSTALL_TEST(_test_loading_libmongocrypt_fails);
}