Skip to content

Commit 8761de4

Browse files
[CDRIVER-4276] On-demand Credentials Callback for CSFLE (#1051)
This implements a credentials callback for client-side encryption. This relates to CDRIVER-4276, although that ticket also concerns itself with server auth on AWS, which is not implemented as part of this change. * Initial simple credentials callback impl * Allow the user-provided callback to set an error * Tests for KMS on-demand callback * Only run callback tests if we have CSE enabled * Add docs for new callback APIs
1 parent f6512fc commit 8761de4

9 files changed

+349
-3
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
:man_page: mongoc_auto_encryption_opts_set_kms_credential_provider_callback
2+
3+
mongoc_auto_encryption_opts_set_kms_credential_provider_callback()
4+
==================================================================
5+
6+
.. versionadded:: 1.23.0
7+
8+
Synopsis
9+
--------
10+
11+
.. code-block:: c
12+
13+
void
14+
mongoc_auto_encryption_opts_set_kms_credential_provider_callback(
15+
mongoc_auto_encryption_opts_t *opts,
16+
mongoc_kms_credentials_provider_callback_fn fn,
17+
void *userdata);
18+
19+
Set the user-provided callback to provide KMS credentials on-demand when they
20+
are needed.
21+
22+
Parameters
23+
----------
24+
25+
- ``opts`` - The options object to update.
26+
- ``fn`` - The provider callback to set on the options object. May be ``NULL``
27+
to clear the callback. Refer to:
28+
:c:type:`mongoc_kms_credentials_provider_callback_fn`
29+
- ``userdata`` - An arbitrary pointer that will be passed along to the
30+
callback function when it is called by libmongoc.
31+
32+
.. seealso:: :doc:`mongoc_client_encryption_opts_set_kms_credential_provider_callback`

src/libmongoc/doc/mongoc_auto_encryption_opts_t.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Synopsis
3131
mongoc_auto_encryption_opts_set_keyvault_client_pool
3232
mongoc_auto_encryption_opts_set_keyvault_namespace
3333
mongoc_auto_encryption_opts_set_kms_providers
34+
mongoc_auto_encryption_opts_set_kms_credential_provider_callback
3435
mongoc_auto_encryption_opts_set_schema_map
3536
mongoc_auto_encryption_opts_set_bypass_auto_encryption
3637
mongoc_auto_encryption_opts_set_extra
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
:man_page: mongoc_client_encryption_opts_set_kms_credential_provider_callback
2+
3+
mongoc_client_encryption_opts_set_kms_credential_provider_callback ()
4+
=====================================================================
5+
6+
.. versionadded:: 1.23.0
7+
8+
Synopsis
9+
--------
10+
11+
.. code-block:: c
12+
13+
void
14+
mongoc_client_encryption_opts_set_kms_credential_provider_callback (
15+
mongoc_client_encryption_opts_t *opts,
16+
mongoc_kms_credentials_provider_callback_fn fn,
17+
void *userdata);
18+
19+
Set the user-provided callback to provide KMS credentials on-demand when they
20+
are needed.
21+
22+
Parameters
23+
----------
24+
25+
- ``opts`` - The options object to update.
26+
- ``fn`` - The provider callback to set on the options object. May be ``NULL``
27+
to clear the callback. Refer to:
28+
:c:type:`mongoc_kms_credentials_provider_callback_fn`
29+
- ``userdata`` - An arbitrary pointer that will be passed along to the
30+
callback function when it is called by libmongoc.
31+
32+
.. seealso:: :doc:`mongoc_auto_encryption_opts_set_kms_credential_provider_callback`
33+
34+
.. rubric:: Related:
35+
36+
.. c:type:: mongoc_kms_credentials_provider_callback_fn
37+
38+
.. code-block:: c
39+
40+
typedef
41+
bool (*mongoc_kms_credentials_provider_callback_fn) (void *userdata,
42+
const bson_t *params,
43+
bson_t *out,
44+
bson_error_t *error);
45+
46+
The type of a callback function for providing KMS providers data on-demand.
47+
48+
:parameters:
49+
50+
- ``userdata`` - The same userdata pointer provided to the ``userdata``
51+
parameter when the callback was set.
52+
- ``params`` - Parameters for the requested KMS credentials. Currently
53+
empty.
54+
- ``out`` - The output :symbol:`bson:bson_t` in which to write the new
55+
KMS providers. When passed to the callback, this already points to an
56+
empty BSON document which must be populated.
57+
- ``error`` - An output parameter for indicating any errors that might
58+
occur while generating the KMS credentials.
59+
60+
:return value: Must return ``true`` on success, ``false`` on failure.

src/libmongoc/doc/mongoc_client_encryption_opts_t.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Used to set options for :symbol:`mongoc_client_encryption_new()`.
2525
mongoc_client_encryption_opts_destroy
2626
mongoc_client_encryption_opts_set_keyvault_client
2727
mongoc_client_encryption_opts_set_keyvault_namespace
28+
mongoc_client_encryption_opts_set_kms_credential_provider_callback
2829
mongoc_client_encryption_opts_set_kms_providers
2930
mongoc_client_encryption_opts_set_tls_opts
3031

src/libmongoc/src/mongoc/mongoc-client-side-encryption.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,20 @@ struct _mongoc_auto_encryption_opts_t {
4545
bson_t *encrypted_fields_map;
4646
bool bypass_auto_encryption;
4747
bool bypass_query_analysis;
48+
mc_kms_credentials_callback creds_cb;
4849
bson_t *extra;
4950
};
5051

52+
static void
53+
_set_creds_callback (mc_kms_credentials_callback *cb,
54+
mongoc_kms_credentials_provider_callback_fn fn,
55+
void *userdata)
56+
{
57+
BSON_ASSERT (cb);
58+
cb->fn = fn;
59+
cb->userdata = userdata;
60+
}
61+
5162
mongoc_auto_encryption_opts_t *
5263
mongoc_auto_encryption_opts_new (void)
5364
{
@@ -206,6 +217,15 @@ mongoc_auto_encryption_opts_set_extra (mongoc_auto_encryption_opts_t *opts,
206217
}
207218
}
208219

220+
void
221+
mongoc_auto_encryption_opts_set_kms_credential_provider_callback (
222+
mongoc_auto_encryption_opts_t *opts,
223+
mongoc_kms_credentials_provider_callback_fn fn,
224+
void *userdata)
225+
{
226+
_set_creds_callback (&opts->creds_cb, fn, userdata);
227+
}
228+
209229
/*--------------------------------------------------------------------------
210230
* Client Encryption options.
211231
*--------------------------------------------------------------------------
@@ -216,6 +236,7 @@ struct _mongoc_client_encryption_opts_t {
216236
char *keyvault_coll;
217237
bson_t *kms_providers;
218238
bson_t *tls_opts;
239+
mc_kms_credentials_callback creds_cb;
219240
};
220241

221242
mongoc_client_encryption_opts_t *
@@ -230,6 +251,7 @@ mongoc_client_encryption_opts_destroy (mongoc_client_encryption_opts_t *opts)
230251
if (!opts) {
231252
return;
232253
}
254+
_set_creds_callback (&opts->creds_cb, NULL, NULL);
233255
bson_free (opts->keyvault_db);
234256
bson_free (opts->keyvault_coll);
235257
bson_destroy (opts->kms_providers);
@@ -287,6 +309,17 @@ mongoc_client_encryption_opts_set_tls_opts (
287309
opts->tls_opts = _bson_copy_or_null (tls_opts);
288310
}
289311

312+
void
313+
mongoc_client_encryption_opts_set_kms_credential_provider_callback (
314+
mongoc_client_encryption_opts_t *opts,
315+
mongoc_kms_credentials_provider_callback_fn fn,
316+
void *userdata)
317+
{
318+
BSON_ASSERT_PARAM (opts);
319+
opts->creds_cb.fn = fn;
320+
opts->creds_cb.userdata = userdata;
321+
}
322+
290323
/*--------------------------------------------------------------------------
291324
* Data key options.
292325
*--------------------------------------------------------------------------
@@ -1551,6 +1584,7 @@ _mongoc_cse_client_enable_auto_encryption (mongoc_client_t *client,
15511584
.extraOptions.cryptSharedLibRequired,
15521585
opts->bypass_auto_encryption,
15531586
opts->bypass_query_analysis,
1587+
opts->creds_cb,
15541588
error);
15551589
if (!client->topology->crypt) {
15561590
GOTO (fail);
@@ -1712,6 +1746,7 @@ _mongoc_cse_client_pool_enable_auto_encryption (
17121746
.cryptSharedLibRequired,
17131747
opts->bypass_auto_encryption,
17141748
opts->bypass_query_analysis,
1749+
opts->creds_cb,
17151750
error);
17161751
if (!topology->crypt) {
17171752
GOTO (fail);
@@ -1817,11 +1852,14 @@ mongoc_client_encryption_new (mongoc_client_encryption_opts_t *opts,
18171852
NULL /* No crypt_shared path */,
18181853
false /* crypt_shared not requried */,
18191854
true, /* bypassAutoEncryption (We are explicit) */
1820-
false /* bypass_query_analysis. Not applicable. */,
1855+
false,
1856+
/* bypass_query_analysis. Not applicable. */
1857+
opts->creds_cb,
18211858
error);
18221859
if (!client_encryption->crypt) {
18231860
goto fail;
18241861
}
1862+
18251863
success = true;
18261864

18271865
fail:

src/libmongoc/src/mongoc/mongoc-client-side-encryption.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ BSON_BEGIN_DECLS
4040

4141
typedef struct _mongoc_auto_encryption_opts_t mongoc_auto_encryption_opts_t;
4242

43+
typedef bool (*mongoc_kms_credentials_provider_callback_fn) (
44+
void *userdata, const bson_t *params, bson_t *out, bson_error_t *error);
45+
4346
MONGOC_EXPORT (mongoc_auto_encryption_opts_t *)
4447
mongoc_auto_encryption_opts_new (void) BSON_GNUC_WARN_UNUSED_RESULT;
4548

@@ -86,6 +89,12 @@ MONGOC_EXPORT (void)
8689
mongoc_auto_encryption_opts_set_extra (mongoc_auto_encryption_opts_t *opts,
8790
const bson_t *extra);
8891

92+
MONGOC_EXPORT (void)
93+
mongoc_auto_encryption_opts_set_kms_credential_provider_callback (
94+
mongoc_auto_encryption_opts_t *opts,
95+
mongoc_kms_credentials_provider_callback_fn fn,
96+
void *userdata);
97+
8998
typedef struct _mongoc_client_encryption_opts_t mongoc_client_encryption_opts_t;
9099
typedef struct _mongoc_client_encryption_t mongoc_client_encryption_t;
91100
typedef struct _mongoc_client_encryption_encrypt_opts_t
@@ -118,6 +127,12 @@ MONGOC_EXPORT (void)
118127
mongoc_client_encryption_opts_set_tls_opts (
119128
mongoc_client_encryption_opts_t *opts, const bson_t *tls_opts);
120129

130+
MONGOC_EXPORT (void)
131+
mongoc_client_encryption_opts_set_kms_credential_provider_callback (
132+
mongoc_client_encryption_opts_t *opts,
133+
mongoc_kms_credentials_provider_callback_fn fn,
134+
void *userdata);
135+
121136
MONGOC_EXPORT (mongoc_client_encryption_rewrap_many_datakey_result_t *)
122137
mongoc_client_encryption_rewrap_many_datakey_result_new (void)
123138
BSON_GNUC_WARN_UNUSED_RESULT;

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@
2121

2222
#include "mongoc-config.h"
2323

24-
#ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION
25-
2624
#include "mongoc.h"
2725

26+
typedef struct mc_kms_credentials_callback {
27+
mongoc_kms_credentials_provider_callback_fn fn;
28+
void *userdata;
29+
} mc_kms_credentials_callback;
30+
31+
#ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION
32+
2833
/* For interacting with libmongocrypt */
2934
typedef struct __mongoc_crypt_t _mongoc_crypt_t;
3035

@@ -42,6 +47,7 @@ _mongoc_crypt_new (const bson_t *kms_providers,
4247
bool crypt_shared_lib_required,
4348
bool bypass_auto_encryption,
4449
bool bypass_query_analysis,
50+
mc_kms_credentials_callback creds_cb,
4551
bson_error_t *error);
4652

4753
void

src/libmongoc/src/mongoc/mongoc-crypt.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct __mongoc_crypt_t {
3535
mongoc_ssl_opt_t aws_tls_opt;
3636
mongoc_ssl_opt_t azure_tls_opt;
3737
mongoc_ssl_opt_t gcp_tls_opt;
38+
mc_kms_credentials_callback creds_cb;
3839
};
3940

4041
static void
@@ -575,6 +576,37 @@ _state_need_kms (_state_machine_t *state_machine, bson_error_t *error)
575576
#undef BUFFER_SIZE
576577
}
577578

579+
static bool
580+
_state_need_kms_credentials (_state_machine_t *sm, bson_error_t *error)
581+
{
582+
bson_t creds = BSON_INITIALIZER;
583+
BSON_ASSERT (sm->crypt->creds_cb.fn);
584+
const bson_t empty = BSON_INITIALIZER;
585+
586+
if (!sm->crypt->creds_cb.fn (
587+
sm->crypt->creds_cb.userdata, &empty, &creds, error)) {
588+
// The callback reports that it has failed
589+
if (!error->code) {
590+
bson_set_error (error,
591+
MONGOC_ERROR_CLIENT_SIDE_ENCRYPTION,
592+
MONGOC_ERROR_CLIENT_INVALID_ENCRYPTION_ARG,
593+
"Unknown error from user-provided callback for "
594+
"on-demand KMS credentials");
595+
}
596+
return false;
597+
}
598+
599+
mongocrypt_binary_t *data = mongocrypt_binary_new_from_data (
600+
(uint8_t *) bson_get_data (&creds), creds.len);
601+
bool okay = mongocrypt_ctx_provide_kms_providers (sm->ctx, data);
602+
if (!okay) {
603+
_ctx_check_error (sm->ctx, error, true);
604+
}
605+
mongocrypt_binary_destroy (data);
606+
bson_destroy (&creds);
607+
return okay;
608+
}
609+
578610
static bool
579611
_state_ready (_state_machine_t *state_machine,
580612
bson_t *result,
@@ -651,6 +683,11 @@ _state_machine_run (_state_machine_t *state_machine,
651683
goto fail;
652684
}
653685
break;
686+
case MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS:
687+
if (!_state_need_kms_credentials (state_machine, error)) {
688+
goto fail;
689+
}
690+
break;
654691
case MONGOCRYPT_CTX_READY:
655692
bson_destroy (result);
656693
if (!_state_ready (state_machine, result, error)) {
@@ -914,6 +951,7 @@ _mongoc_crypt_new (const bson_t *kms_providers,
914951
bool crypt_shared_lib_required,
915952
bool bypass_auto_encryption,
916953
bool bypass_query_analysis,
954+
mc_kms_credentials_callback creds_cb,
917955
bson_error_t *error)
918956
{
919957
_mongoc_crypt_t *crypt;
@@ -941,6 +979,12 @@ _mongoc_crypt_new (const bson_t *kms_providers,
941979
goto fail;
942980
}
943981

982+
if (creds_cb.fn) {
983+
// The user has provided a callback to lazily obtain KMS credentials. We
984+
// need to opt-in to the libmongocrypt feature.
985+
mongocrypt_setopt_use_need_kms_credentials_state (crypt->handle);
986+
}
987+
944988
if (schema_map) {
945989
schema_map_bin = mongocrypt_binary_new_from_data (
946990
(uint8_t *) bson_get_data (schema_map), schema_map->len);
@@ -1010,6 +1054,8 @@ _mongoc_crypt_new (const bson_t *kms_providers,
10101054
s);
10111055
}
10121056

1057+
crypt->creds_cb = creds_cb;
1058+
10131059
success = true;
10141060
fail:
10151061
mongocrypt_binary_destroy (local_masterkey_bin);

0 commit comments

Comments
 (0)