Skip to content

Commit a618423

Browse files
authored
CDRIVER-4222 add _mongoc_ssl_opts_from_bson (#886)
1 parent e16cc6f commit a618423

File tree

5 files changed

+305
-0
lines changed

5 files changed

+305
-0
lines changed

src/libmongoc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,7 @@ set (test-libmongoc-sources
993993
${PROJECT_SOURCE_DIR}/tests/test-mongoc-shared.c
994994
${PROJECT_SOURCE_DIR}/tests/test-mongoc-socket.c
995995
${PROJECT_SOURCE_DIR}/tests/test-mongoc-speculative-auth.c
996+
${PROJECT_SOURCE_DIR}/tests/test-mongoc-ssl.c
996997
${PROJECT_SOURCE_DIR}/tests/test-mongoc-stream.c
997998
${PROJECT_SOURCE_DIR}/tests/test-mongoc-streamable-hello.c
998999
${PROJECT_SOURCE_DIR}/tests/test-mongoc-thread.c

src/libmongoc/src/mongoc/mongoc-ssl-private.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ _mongoc_ssl_opts_disable_ocsp_endpoint_check (const mongoc_ssl_opt_t *ssl_opt);
5252
void
5353
_mongoc_ssl_opts_cleanup (mongoc_ssl_opt_t *opt, bool free_internal);
5454

55+
/* _mongoc_ssl_opts_from_bson is an internal helper for constructing an ssl_opt
56+
* from a BSON document. It is used to parse TLS options for the KMIP KMS
57+
* provider in CSFLE.
58+
* - ssl_opt must be a zero'd out ssl_opt struct.
59+
* - errmsg must be an initialized bson_string_t.
60+
* - Returns false on error and appends to errmsg. */
61+
bool
62+
_mongoc_ssl_opts_from_bson (mongoc_ssl_opt_t *ssl_opt,
63+
const bson_t *bson,
64+
bson_string_t *errmsg);
65+
5566
BSON_END_DECLS
5667

5768

src/libmongoc/src/mongoc/mongoc-ssl.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "mongoc-ssl-private.h"
2424
#include "mongoc-log.h"
2525
#include "mongoc-uri.h"
26+
#include "mongoc-util-private.h"
2627

2728
#if defined(MONGOC_ENABLE_SSL_OPENSSL)
2829
#include "mongoc-openssl-private.h"
@@ -178,5 +179,89 @@ _mongoc_ssl_opts_disable_ocsp_endpoint_check (const mongoc_ssl_opt_t *ssl_opt)
178179
->tls_disable_ocsp_endpoint_check;
179180
}
180181

182+
bool
183+
_mongoc_ssl_opts_from_bson (mongoc_ssl_opt_t *ssl_opt,
184+
const bson_t *bson,
185+
bson_string_t *errmsg)
186+
{
187+
bson_iter_t iter;
188+
189+
if (ssl_opt->internal) {
190+
bson_string_append (errmsg,
191+
"SSL options must not have internal state set");
192+
return false;
193+
}
194+
195+
ssl_opt->internal = bson_malloc0 (sizeof (_mongoc_internal_tls_opts_t));
196+
197+
if (!bson_iter_init (&iter, bson)) {
198+
bson_string_append (errmsg,
199+
"error initializing iterator to BSON SSL options");
200+
return false;
201+
}
202+
203+
while (bson_iter_next (&iter)) {
204+
const char *key = bson_iter_key (&iter);
205+
206+
if (BSON_ITER_HOLDS_UTF8 (&iter)) {
207+
if (0 == bson_strcasecmp (key, MONGOC_URI_TLSCERTIFICATEKEYFILE)) {
208+
ssl_opt->pem_file = bson_strdup (bson_iter_utf8 (&iter, NULL));
209+
continue;
210+
} else if (0 == bson_strcasecmp (
211+
key, MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD)) {
212+
ssl_opt->pem_pwd = bson_strdup (bson_iter_utf8 (&iter, NULL));
213+
continue;
214+
} else if (0 == bson_strcasecmp (key, MONGOC_URI_TLSCAFILE)) {
215+
ssl_opt->ca_file = bson_strdup (bson_iter_utf8 (&iter, NULL));
216+
continue;
217+
}
218+
}
219+
220+
if (BSON_ITER_HOLDS_BOOL (&iter)) {
221+
if (0 ==
222+
bson_strcasecmp (key, MONGOC_URI_TLSALLOWINVALIDCERTIFICATES)) {
223+
/* If MONGOC_URI_TLSINSECURE was parsed, weak_cert_validation must
224+
* remain true. */
225+
ssl_opt->weak_cert_validation =
226+
ssl_opt->weak_cert_validation || bson_iter_bool (&iter);
227+
continue;
228+
} else if (0 == bson_strcasecmp (
229+
key, MONGOC_URI_TLSALLOWINVALIDHOSTNAMES)) {
230+
/* If MONGOC_URI_TLSINSECURE was parsed, allow_invalid_hostname must
231+
* remain true. */
232+
ssl_opt->allow_invalid_hostname =
233+
ssl_opt->allow_invalid_hostname || bson_iter_bool (&iter);
234+
continue;
235+
} else if (0 == bson_strcasecmp (key, MONGOC_URI_TLSINSECURE)) {
236+
if (bson_iter_bool (&iter)) {
237+
ssl_opt->weak_cert_validation = true;
238+
ssl_opt->allow_invalid_hostname = true;
239+
}
240+
continue;
241+
} else if (0 ==
242+
bson_strcasecmp (
243+
key, MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK)) {
244+
((_mongoc_internal_tls_opts_t *) ssl_opt->internal)
245+
->tls_disable_certificate_revocation_check =
246+
bson_iter_bool (&iter);
247+
continue;
248+
} else if (0 == bson_strcasecmp (
249+
key, MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK)) {
250+
((_mongoc_internal_tls_opts_t *) ssl_opt->internal)
251+
->tls_disable_ocsp_endpoint_check = bson_iter_bool (&iter);
252+
continue;
253+
}
254+
}
255+
256+
bson_string_append_printf (
257+
errmsg,
258+
"unexpected %s option: %s",
259+
_mongoc_bson_type_to_str (bson_iter_type (&iter)),
260+
key);
261+
return false;
262+
}
263+
264+
return true;
265+
}
181266

182267
#endif

src/libmongoc/tests/test-libmongoc.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ extern void
282282
test_generation_map_install (TestSuite *suite);
283283
extern void
284284
test_shared_install (TestSuite *suite);
285+
extern void
286+
test_ssl_install (TestSuite *suite);
285287

286288
typedef struct {
287289
mongoc_log_level_t level;
@@ -2960,6 +2962,7 @@ main (int argc, char *argv[])
29602962
test_server_stream_install (&suite);
29612963
test_generation_map_install (&suite);
29622964
test_shared_install (&suite);
2965+
test_ssl_install (&suite);
29632966

29642967
if (test_framework_is_loadbalanced ()) {
29652968
mongoc_global_mock_service_id = true;

src/libmongoc/tests/test-mongoc-ssl.c

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* Copyright 2021-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "TestSuite.h"
18+
#include "mongoc-config.h"
19+
#include "test-conveniences.h"
20+
21+
#ifdef MONGOC_ENABLE_SSL
22+
#include "mongoc-ssl-private.h"
23+
24+
typedef struct {
25+
const char *description;
26+
const char *bson;
27+
const char *expect_error;
28+
const char *expect_pem_file;
29+
const char *expect_pem_pwd;
30+
const char *expect_ca_file;
31+
bool expect_weak_cert_validation;
32+
bool expect_allow_invalid_hostname;
33+
bool expect_disable_ocsp_endpoint_check;
34+
bool expect_disable_certificate_revocation_check;
35+
} testcase_t;
36+
37+
/*
38+
The following are the only valid options for _mongoc_ssl_opts_from_bson:
39+
40+
MONGOC_URI_TLSCERTIFICATEKEYFILE "tlscertificatekeyfile"
41+
MONGOC_URI_TLSCERTIFICATEKEYFILEPASSWORD "tlscertificatekeyfilepassword"
42+
MONGOC_URI_TLSCAFILE "tlscafile"
43+
MONGOC_URI_TLSALLOWINVALIDCERTIFICATES "tlsallowinvalidcertificates"
44+
MONGOC_URI_TLSALLOWINVALIDHOSTNAMES "tlsallowinvalidhostnames"
45+
MONGOC_URI_TLSINSECURE "tlsinsecure"
46+
MONGOC_URI_TLSDISABLECERTIFICATEREVOCATIONCHECK
47+
"tlsdisablecertificaterevocationcheck"
48+
MONGOC_URI_TLSDISABLEOCSPENDPOINTCHECK "tlsdisableocspendpointcheck"
49+
*/
50+
51+
static void
52+
test_mongoc_ssl_opts_from_bson (void)
53+
{
54+
testcase_t tests[] = {
55+
{
56+
"test all options set",
57+
"{'tlsCertificateKeyFile': 'test_pem_file', "
58+
"'tlsCertificateKeyFilePassword': 'test_pem_pwd', 'tlsCAFile': "
59+
"'test_ca_file', 'tlsAllowInvalidCertificates': true, "
60+
"'tlsAllowInvalidHostnames': true, 'tlsInsecure': true, "
61+
"'tlsDisableCertificateRevocationCheck': true, "
62+
"'tlsDisableOCSPEndpointCheck': true }",
63+
NULL /* expect_error */,
64+
"test_pem_file" /* pem_file */,
65+
"test_pem_pwd" /* pem_pwd */,
66+
"test_ca_file" /* ca_file */,
67+
true /* weak_cert_validation */,
68+
true /* allow_invalid_hostname */,
69+
true /* disable_ocsp_endpoint_check */,
70+
true /* disable_certificate_revocation_check */
71+
},
72+
{
73+
"test options are case insentive",
74+
"{'tlscertificatekeyfile': 'test_pem_file', "
75+
"'tlscertificatekeyfilepassword': 'test_pem_pwd', 'tlscafile': "
76+
"'test_ca_file', 'tlsallowinvalidcertificates': true, "
77+
"'tlsallowinvalidhostnames': true, 'tlsinsecure': true, "
78+
"'tlsdisablecertificaterevocationcheck': true, "
79+
"'tlsdisableocspendpointcheck': true }",
80+
NULL /* expect_error */,
81+
"test_pem_file" /* pem_file */,
82+
"test_pem_pwd" /* pem_pwd */,
83+
"test_ca_file" /* ca_file */,
84+
true /* weak_cert_validation */,
85+
true /* allow_invalid_hostname */,
86+
true /* disable_ocsp_endpoint_check */,
87+
true /* disable_certificate_revocation_check */
88+
},
89+
{
90+
"test no options set",
91+
"{}",
92+
NULL /* expect_error */,
93+
NULL /* pem_file */,
94+
NULL /* pem_pwd */,
95+
NULL /* ca_file */,
96+
false /* weak_cert_validation */,
97+
false /* allow_invalid_hostname */,
98+
false /* disable_ocsp_endpoint_check */,
99+
false /* disable_certificate_revocation_check */
100+
},
101+
{
102+
"test tlsInsecure overrides tlsAllowInvalidHostnames and "
103+
"tlsAllowInvalidCertificates set",
104+
"{'tlsInsecure': true, 'tlsAllowInvalidHostnames': false, "
105+
"'tlsAllowInvalidCertificates': false}",
106+
NULL /* expect_error */,
107+
NULL /* pem_file */,
108+
NULL /* pem_pwd */,
109+
NULL /* ca_file */,
110+
true /* weak_cert_validation */,
111+
true /* allow_invalid_hostname */,
112+
false /* disable_ocsp_endpoint_check */,
113+
false /* disable_certificate_revocation_check */
114+
},
115+
{
116+
"test unrecognized option",
117+
"{'foo': true }",
118+
"unexpected BOOL option: foo" /* expect_error */,
119+
NULL /* pem_file */,
120+
NULL /* pem_pwd */,
121+
NULL /* ca_file */,
122+
false /* weak_cert_validation */,
123+
false /* allow_invalid_hostname */,
124+
false /* disable_ocsp_endpoint_check */,
125+
false /* disable_certificate_revocation_check */
126+
},
127+
{
128+
"test wrong value type",
129+
"{'tlsCaFile': true }",
130+
"unexpected BOOL option: tlsCaFile" /* expect_error */,
131+
NULL /* pem_file */,
132+
NULL /* pem_pwd */,
133+
NULL /* ca_file */,
134+
false /* weak_cert_validation */,
135+
false /* allow_invalid_hostname */,
136+
false /* disable_ocsp_endpoint_check */,
137+
false /* disable_certificate_revocation_check */
138+
},
139+
{0}};
140+
testcase_t *test;
141+
142+
for (test = tests; test->bson != NULL; test++) {
143+
mongoc_ssl_opt_t ssl_opt = {0};
144+
bson_string_t *errmsg = bson_string_new (NULL);
145+
bool ok =
146+
_mongoc_ssl_opts_from_bson (&ssl_opt, tmp_bson (test->bson), errmsg);
147+
148+
MONGOC_DEBUG ("testcase: %s", test->bson);
149+
if (test->expect_error) {
150+
ASSERT_CONTAINS (errmsg->str, test->expect_error);
151+
ASSERT (!ok);
152+
} else {
153+
if (!ok) {
154+
test_error ("unexpected error parsing: %s", errmsg->str);
155+
}
156+
}
157+
158+
if (!test->expect_pem_file) {
159+
ASSERT (!ssl_opt.pem_file);
160+
} else {
161+
ASSERT (ssl_opt.pem_file);
162+
ASSERT_CMPSTR (test->expect_pem_file, ssl_opt.pem_file);
163+
}
164+
165+
if (!test->expect_pem_pwd) {
166+
ASSERT (!ssl_opt.pem_pwd);
167+
} else {
168+
ASSERT (ssl_opt.pem_pwd);
169+
ASSERT_CMPSTR (test->expect_pem_pwd, ssl_opt.pem_pwd);
170+
}
171+
172+
if (!test->expect_ca_file) {
173+
ASSERT (!ssl_opt.ca_file);
174+
} else {
175+
ASSERT (ssl_opt.ca_file);
176+
ASSERT_CMPSTR (test->expect_ca_file, ssl_opt.ca_file);
177+
}
178+
179+
ASSERT (test->expect_weak_cert_validation ==
180+
ssl_opt.weak_cert_validation);
181+
ASSERT (test->expect_allow_invalid_hostname ==
182+
ssl_opt.allow_invalid_hostname);
183+
ASSERT (test->expect_disable_ocsp_endpoint_check ==
184+
_mongoc_ssl_opts_disable_ocsp_endpoint_check (&ssl_opt));
185+
ASSERT (test->expect_disable_certificate_revocation_check ==
186+
_mongoc_ssl_opts_disable_certificate_revocation_check (&ssl_opt));
187+
188+
/* It is not possible to set ca_dir or crl_file. */
189+
ASSERT (!ssl_opt.ca_dir);
190+
ASSERT (!ssl_opt.crl_file);
191+
192+
_mongoc_ssl_opts_cleanup (&ssl_opt, true /* free_internal */);
193+
bson_string_free (errmsg, true /* free_segment */);
194+
}
195+
}
196+
197+
#endif /* MONGOC_ENABLE_SSL */
198+
199+
void
200+
test_ssl_install (TestSuite *suite)
201+
{
202+
#ifdef MONGOC_ENABLE_SSL
203+
TestSuite_Add (suite, "/ssl_opt/from_bson", test_mongoc_ssl_opts_from_bson);
204+
#endif /* MONGOC_ENABLE_SSL */
205+
}

0 commit comments

Comments
 (0)