1 /*
2 * Copyright 2019-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 <bson/bson.h>
18
19 #include "mongocrypt-ctx-private.h"
20 #include "mongocrypt-key-broker-private.h"
21
22 #define ALGORITHM_DETERMINISTIC "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
23 #define ALGORITHM_DETERMINISTIC_LEN 43
24 #define ALGORITHM_RANDOM "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
25 #define ALGORITHM_RANDOM_LEN 36
26
27 bool
_mongocrypt_ctx_fail_w_msg(mongocrypt_ctx_t * ctx,const char * msg)28 _mongocrypt_ctx_fail_w_msg (mongocrypt_ctx_t *ctx, const char *msg)
29 {
30 _mongocrypt_set_error (ctx->status,
31 MONGOCRYPT_STATUS_ERROR_CLIENT,
32 MONGOCRYPT_GENERIC_ERROR_CODE,
33 "%s",
34 msg);
35 return _mongocrypt_ctx_fail (ctx);
36 }
37
38 /* A failure status has already been set. */
39 bool
_mongocrypt_ctx_fail(mongocrypt_ctx_t * ctx)40 _mongocrypt_ctx_fail (mongocrypt_ctx_t *ctx)
41 {
42 if (mongocrypt_status_ok (ctx->status)) {
43 return _mongocrypt_ctx_fail_w_msg (
44 ctx, "unexpected, failing but no error status set");
45 }
46 ctx->state = MONGOCRYPT_CTX_ERROR;
47 return false;
48 }
49
50
51 static bool
_set_binary_opt(mongocrypt_ctx_t * ctx,mongocrypt_binary_t * binary,_mongocrypt_buffer_t * buf,bson_subtype_t subtype)52 _set_binary_opt (mongocrypt_ctx_t *ctx,
53 mongocrypt_binary_t *binary,
54 _mongocrypt_buffer_t *buf,
55 bson_subtype_t subtype)
56 {
57 BSON_ASSERT (ctx);
58
59 if (ctx->state == MONGOCRYPT_CTX_ERROR) {
60 return false;
61 }
62
63 if (!binary || !binary->data) {
64 return _mongocrypt_ctx_fail_w_msg (ctx, "option must be non-NULL");
65 }
66
67 if (!_mongocrypt_buffer_empty (buf)) {
68 return _mongocrypt_ctx_fail_w_msg (ctx, "option already set");
69 }
70
71 if (ctx->initialized) {
72 return _mongocrypt_ctx_fail_w_msg (ctx, "cannot set options after init");
73 }
74
75 if (subtype == BSON_SUBTYPE_UUID && binary->len != 16) {
76 return _mongocrypt_ctx_fail_w_msg (ctx, "expected 16 byte UUID");
77 }
78
79 _mongocrypt_buffer_copy_from_binary (buf, binary);
80 buf->subtype = subtype;
81
82 return true;
83 }
84
85
86 bool
mongocrypt_ctx_setopt_key_id(mongocrypt_ctx_t * ctx,mongocrypt_binary_t * key_id)87 mongocrypt_ctx_setopt_key_id (mongocrypt_ctx_t *ctx,
88 mongocrypt_binary_t *key_id)
89 {
90 if (!ctx) {
91 return false;
92 }
93
94 if (ctx->crypt->log.trace_enabled && key_id && key_id->data) {
95 char *key_id_val;
96 key_id_val =
97 _mongocrypt_new_string_from_bytes (key_id->data, key_id->len);
98 _mongocrypt_log (&ctx->crypt->log,
99 MONGOCRYPT_LOG_LEVEL_TRACE,
100 "%s (%s=\"%s\")",
101 BSON_FUNC,
102 "key_id",
103 key_id_val);
104 bson_free (key_id_val);
105 }
106
107 return _set_binary_opt (ctx, key_id, &ctx->opts.key_id, BSON_SUBTYPE_UUID);
108 }
109
110
111 bool
mongocrypt_ctx_setopt_key_alt_name(mongocrypt_ctx_t * ctx,mongocrypt_binary_t * key_alt_name)112 mongocrypt_ctx_setopt_key_alt_name (mongocrypt_ctx_t *ctx,
113 mongocrypt_binary_t *key_alt_name)
114 {
115 bson_t as_bson;
116 bson_iter_t iter;
117 _mongocrypt_key_alt_name_t *new_key_alt_name;
118 const char *key;
119
120 if (!ctx) {
121 return false;
122 }
123
124 if (ctx->initialized) {
125 return _mongocrypt_ctx_fail_w_msg (ctx, "cannot set options after init");
126 }
127
128 if (ctx->state == MONGOCRYPT_CTX_ERROR) {
129 return false;
130 }
131
132 if (!key_alt_name || !key_alt_name->data) {
133 return _mongocrypt_ctx_fail_w_msg (ctx, "option must be non-NULL");
134 }
135
136 if (!_mongocrypt_binary_to_bson (key_alt_name, &as_bson)) {
137 return _mongocrypt_ctx_fail_w_msg (ctx, "invalid keyAltName bson object");
138 }
139
140 if (!bson_iter_init (&iter, &as_bson) || !bson_iter_next (&iter)) {
141 return _mongocrypt_ctx_fail_w_msg (ctx, "invalid bson");
142 }
143
144 key = bson_iter_key (&iter);
145 BSON_ASSERT (key);
146 if (0 != strcmp (key, "keyAltName")) {
147 return _mongocrypt_ctx_fail_w_msg (
148 ctx, "keyAltName must have field 'keyAltName'");
149 }
150
151 if (!BSON_ITER_HOLDS_UTF8 (&iter)) {
152 return _mongocrypt_ctx_fail_w_msg (ctx, "keyAltName expected to be UTF8");
153 }
154
155 new_key_alt_name = _mongocrypt_key_alt_name_new (bson_iter_value (&iter));
156
157 if (ctx->opts.key_alt_names &&
158 _mongocrypt_key_alt_name_intersects (ctx->opts.key_alt_names,
159 new_key_alt_name)) {
160 _mongocrypt_key_alt_name_destroy_all (new_key_alt_name);
161 return _mongocrypt_ctx_fail_w_msg (ctx, "duplicate keyAltNames found");
162 }
163 new_key_alt_name->next = ctx->opts.key_alt_names;
164 ctx->opts.key_alt_names = new_key_alt_name;
165
166 if (bson_iter_next (&iter)) {
167 return _mongocrypt_ctx_fail_w_msg (
168 ctx, "unrecognized field, only keyAltName expected");
169 }
170
171 return true;
172 }
173
174
175 bool
mongocrypt_ctx_setopt_algorithm(mongocrypt_ctx_t * ctx,const char * algorithm,int len)176 mongocrypt_ctx_setopt_algorithm (mongocrypt_ctx_t *ctx,
177 const char *algorithm,
178 int len)
179 {
180 size_t calculated_len;
181
182 if (!ctx) {
183 return false;
184 }
185
186 if (ctx->initialized) {
187 return _mongocrypt_ctx_fail_w_msg (ctx, "cannot set options after init");
188 }
189
190 if (ctx->state == MONGOCRYPT_CTX_ERROR) {
191 return false;
192 }
193
194 if (ctx->opts.algorithm != MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE) {
195 return _mongocrypt_ctx_fail_w_msg (ctx, "already set algorithm");
196 }
197
198 if (len < -1) {
199 return _mongocrypt_ctx_fail_w_msg (ctx, "invalid algorithm length");
200 }
201
202 if (!algorithm) {
203 return _mongocrypt_ctx_fail_w_msg (ctx, "passed null algorithm");
204 }
205
206 calculated_len = len == -1 ? strlen (algorithm) : (size_t) len;
207 if (ctx->crypt->log.trace_enabled) {
208 _mongocrypt_log (&ctx->crypt->log,
209 MONGOCRYPT_LOG_LEVEL_TRACE,
210 "%s (%s=\"%.*s\")",
211 BSON_FUNC,
212 "algorithm",
213 (int) calculated_len,
214 algorithm);
215 }
216
217 if (calculated_len == ALGORITHM_DETERMINISTIC_LEN &&
218 strncmp (algorithm,
219 ALGORITHM_DETERMINISTIC,
220 ALGORITHM_DETERMINISTIC_LEN) == 0) {
221 ctx->opts.algorithm = MONGOCRYPT_ENCRYPTION_ALGORITHM_DETERMINISTIC;
222 return true;
223 }
224
225 if (calculated_len == ALGORITHM_RANDOM_LEN &&
226 strncmp (algorithm, ALGORITHM_RANDOM, ALGORITHM_RANDOM_LEN) == 0) {
227 ctx->opts.algorithm = MONGOCRYPT_ENCRYPTION_ALGORITHM_RANDOM;
228 return true;
229 }
230
231 return _mongocrypt_ctx_fail_w_msg (ctx, "unsupported algorithm");
232 }
233
234
235 mongocrypt_ctx_t *
mongocrypt_ctx_new(mongocrypt_t * crypt)236 mongocrypt_ctx_new (mongocrypt_t *crypt)
237 {
238 mongocrypt_ctx_t *ctx;
239 int ctx_size;
240
241 if (!crypt) {
242 return NULL;
243 }
244 if (!crypt->initialized) {
245 mongocrypt_status_t *status;
246
247 status = crypt->status;
248 CLIENT_ERR ("cannot create context from uninitialized crypt");
249 return NULL;
250 }
251 ctx_size = sizeof (_mongocrypt_ctx_encrypt_t);
252 if (sizeof (_mongocrypt_ctx_decrypt_t) > ctx_size) {
253 ctx_size = sizeof (_mongocrypt_ctx_decrypt_t);
254 }
255 if (sizeof (_mongocrypt_ctx_datakey_t) > ctx_size) {
256 ctx_size = sizeof (_mongocrypt_ctx_datakey_t);
257 }
258 ctx = bson_malloc0 (ctx_size);
259 BSON_ASSERT (ctx);
260
261 ctx->crypt = crypt;
262 ctx->status = mongocrypt_status_new ();
263 ctx->opts.algorithm = MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE;
264 ctx->state = MONGOCRYPT_CTX_DONE;
265 return ctx;
266 }
267
268 #define CHECK_AND_CALL(fn, ...) \
269 do { \
270 if (!ctx->vtable.fn) { \
271 return _mongocrypt_ctx_fail_w_msg (ctx, "not applicable to context"); \
272 } \
273 return ctx->vtable.fn (__VA_ARGS__); \
274 } while (0)
275
276 /* Common to both encrypt and decrypt context. */
277 static bool
_mongo_op_keys(mongocrypt_ctx_t * ctx,mongocrypt_binary_t * out)278 _mongo_op_keys (mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out)
279 {
280 /* Construct the find filter to fetch keys. */
281 if (!_mongocrypt_key_broker_filter (&ctx->kb, out)) {
282 BSON_ASSERT (!_mongocrypt_key_broker_status (&ctx->kb, ctx->status));
283 return _mongocrypt_ctx_fail (ctx);
284 }
285 return true;
286 }
287
288
289 static bool
_mongo_feed_keys(mongocrypt_ctx_t * ctx,mongocrypt_binary_t * in)290 _mongo_feed_keys (mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in)
291 {
292 _mongocrypt_buffer_t buf;
293
294 _mongocrypt_buffer_from_binary (&buf, in);
295 if (!_mongocrypt_key_broker_add_doc (&ctx->kb, &buf)) {
296 BSON_ASSERT (!_mongocrypt_key_broker_status (&ctx->kb, ctx->status));
297 return _mongocrypt_ctx_fail (ctx);
298 }
299 return true;
300 }
301
302
303 static bool
_mongo_done_keys(mongocrypt_ctx_t * ctx)304 _mongo_done_keys (mongocrypt_ctx_t *ctx)
305 {
306 (void) _mongocrypt_key_broker_docs_done (&ctx->kb);
307 return _mongocrypt_ctx_state_from_key_broker (ctx);
308 }
309
310 static mongocrypt_kms_ctx_t *
_next_kms_ctx(mongocrypt_ctx_t * ctx)311 _next_kms_ctx (mongocrypt_ctx_t *ctx)
312 {
313 return _mongocrypt_key_broker_next_kms (&ctx->kb);
314 }
315
316
317 static bool
_kms_done(mongocrypt_ctx_t * ctx)318 _kms_done (mongocrypt_ctx_t *ctx)
319 {
320 if (!_mongocrypt_key_broker_kms_done (&ctx->kb)) {
321 BSON_ASSERT (!_mongocrypt_key_broker_status (&ctx->kb, ctx->status));
322 return _mongocrypt_ctx_fail (ctx);
323 }
324 ctx->state = MONGOCRYPT_CTX_READY;
325 return true;
326 }
327
328
329 bool
mongocrypt_ctx_mongo_op(mongocrypt_ctx_t * ctx,mongocrypt_binary_t * out)330 mongocrypt_ctx_mongo_op (mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out)
331 {
332 if (!ctx) {
333 return false;
334 }
335 if (!ctx->initialized) {
336 return _mongocrypt_ctx_fail_w_msg (ctx, "ctx NULL or uninitialized");
337 }
338
339 if (!out) {
340 return _mongocrypt_ctx_fail_w_msg (ctx, "invalid NULL input");
341 }
342
343 switch (ctx->state) {
344 case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO:
345 CHECK_AND_CALL (mongo_op_collinfo, ctx, out);
346 case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS:
347 CHECK_AND_CALL (mongo_op_markings, ctx, out);
348 case MONGOCRYPT_CTX_NEED_MONGO_KEYS:
349 CHECK_AND_CALL (mongo_op_keys, ctx, out);
350 case MONGOCRYPT_CTX_ERROR:
351 return false;
352 default:
353 return _mongocrypt_ctx_fail_w_msg (ctx, "wrong state");
354 }
355 }
356
357
358 bool
mongocrypt_ctx_mongo_feed(mongocrypt_ctx_t * ctx,mongocrypt_binary_t * in)359 mongocrypt_ctx_mongo_feed (mongocrypt_ctx_t *ctx, mongocrypt_binary_t *in)
360 {
361 if (!ctx) {
362 return false;
363 }
364 if (!ctx->initialized) {
365 return _mongocrypt_ctx_fail_w_msg (ctx, "ctx NULL or uninitialized");
366 }
367
368 if (!in) {
369 return _mongocrypt_ctx_fail_w_msg (ctx, "invalid NULL input");
370 }
371
372 if (ctx->crypt->log.trace_enabled) {
373 char *in_val;
374
375 in_val = _mongocrypt_new_json_string_from_binary (in);
376 _mongocrypt_log (&ctx->crypt->log,
377 MONGOCRYPT_LOG_LEVEL_TRACE,
378 "%s (%s=\"%s\")",
379 BSON_FUNC,
380 "in",
381 in_val);
382 bson_free (in_val);
383 }
384
385 switch (ctx->state) {
386 case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO:
387 CHECK_AND_CALL (mongo_feed_collinfo, ctx, in);
388 case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS:
389 CHECK_AND_CALL (mongo_feed_markings, ctx, in);
390 case MONGOCRYPT_CTX_NEED_MONGO_KEYS:
391 CHECK_AND_CALL (mongo_feed_keys, ctx, in);
392 case MONGOCRYPT_CTX_ERROR:
393 return false;
394 default:
395 return _mongocrypt_ctx_fail_w_msg (ctx, "wrong state");
396 }
397 }
398
399
400 bool
mongocrypt_ctx_mongo_done(mongocrypt_ctx_t * ctx)401 mongocrypt_ctx_mongo_done (mongocrypt_ctx_t *ctx)
402 {
403 if (!ctx) {
404 return false;
405 }
406 if (!ctx->initialized) {
407 return _mongocrypt_ctx_fail_w_msg (ctx, "ctx NULL or uninitialized");
408 }
409
410 switch (ctx->state) {
411 case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO:
412 CHECK_AND_CALL (mongo_done_collinfo, ctx);
413 case MONGOCRYPT_CTX_NEED_MONGO_MARKINGS:
414 CHECK_AND_CALL (mongo_done_markings, ctx);
415 case MONGOCRYPT_CTX_NEED_MONGO_KEYS:
416 CHECK_AND_CALL (mongo_done_keys, ctx);
417 case MONGOCRYPT_CTX_ERROR:
418 return false;
419 default:
420 return _mongocrypt_ctx_fail_w_msg (ctx, "wrong state");
421 }
422 }
423
424
425 mongocrypt_ctx_state_t
mongocrypt_ctx_state(mongocrypt_ctx_t * ctx)426 mongocrypt_ctx_state (mongocrypt_ctx_t *ctx)
427 {
428 if (!ctx) {
429 return MONGOCRYPT_CTX_ERROR;
430 }
431 if (!ctx->initialized) {
432 _mongocrypt_ctx_fail_w_msg (ctx, "ctx NULL or uninitialized");
433 return MONGOCRYPT_CTX_ERROR;
434 }
435
436 return ctx->state;
437 }
438
439
440 mongocrypt_kms_ctx_t *
mongocrypt_ctx_next_kms_ctx(mongocrypt_ctx_t * ctx)441 mongocrypt_ctx_next_kms_ctx (mongocrypt_ctx_t *ctx)
442 {
443 if (!ctx) {
444 return NULL;
445 }
446 if (!ctx->initialized) {
447 _mongocrypt_ctx_fail_w_msg (ctx, "ctx NULL or uninitialized");
448 return NULL;
449 }
450
451 if (!ctx->vtable.next_kms_ctx) {
452 _mongocrypt_ctx_fail_w_msg (ctx, "not applicable to context");
453 return NULL;
454 }
455
456 switch (ctx->state) {
457 case MONGOCRYPT_CTX_NEED_KMS:
458 return ctx->vtable.next_kms_ctx (ctx);
459 case MONGOCRYPT_CTX_ERROR:
460 return NULL;
461 default:
462 _mongocrypt_ctx_fail_w_msg (ctx, "wrong state");
463 return NULL;
464 }
465 }
466
467
468 bool
mongocrypt_ctx_kms_done(mongocrypt_ctx_t * ctx)469 mongocrypt_ctx_kms_done (mongocrypt_ctx_t *ctx)
470 {
471 if (!ctx) {
472 return false;
473 }
474 if (!ctx->initialized) {
475 return _mongocrypt_ctx_fail_w_msg (ctx, "ctx NULL or uninitialized");
476 }
477
478 if (!ctx->vtable.kms_done) {
479 return _mongocrypt_ctx_fail_w_msg (ctx, "not applicable to context");
480 }
481
482 switch (ctx->state) {
483 case MONGOCRYPT_CTX_NEED_KMS:
484 return ctx->vtable.kms_done (ctx);
485 case MONGOCRYPT_CTX_ERROR:
486 return false;
487 default:
488 return _mongocrypt_ctx_fail_w_msg (ctx, "wrong state");
489 }
490 }
491
492
493 bool
mongocrypt_ctx_finalize(mongocrypt_ctx_t * ctx,mongocrypt_binary_t * out)494 mongocrypt_ctx_finalize (mongocrypt_ctx_t *ctx, mongocrypt_binary_t *out)
495 {
496 if (!ctx) {
497 return false;
498 }
499 if (!ctx->initialized) {
500 return _mongocrypt_ctx_fail_w_msg (ctx, "ctx NULL or uninitialized");
501 }
502
503 if (!out) {
504 return _mongocrypt_ctx_fail_w_msg (ctx, "invalid NULL input");
505 }
506
507 if (!ctx->vtable.finalize) {
508 return _mongocrypt_ctx_fail_w_msg (ctx, "not applicable to context");
509 }
510
511 switch (ctx->state) {
512 case MONGOCRYPT_CTX_READY:
513 return ctx->vtable.finalize (ctx, out);
514 case MONGOCRYPT_CTX_ERROR:
515 return false;
516 default:
517 return _mongocrypt_ctx_fail_w_msg (ctx, "wrong state");
518 }
519 }
520
521 bool
mongocrypt_ctx_status(mongocrypt_ctx_t * ctx,mongocrypt_status_t * out)522 mongocrypt_ctx_status (mongocrypt_ctx_t *ctx, mongocrypt_status_t *out)
523 {
524 if (!ctx) {
525 return false;
526 }
527
528 if (!mongocrypt_status_ok (ctx->status)) {
529 _mongocrypt_status_copy_to (ctx->status, out);
530 return false;
531 }
532 _mongocrypt_status_reset (out);
533 return true;
534 }
535
536
537 void
mongocrypt_ctx_destroy(mongocrypt_ctx_t * ctx)538 mongocrypt_ctx_destroy (mongocrypt_ctx_t *ctx)
539 {
540 if (!ctx) {
541 return;
542 }
543
544 if (ctx->vtable.cleanup) {
545 ctx->vtable.cleanup (ctx);
546 }
547
548 bson_free (ctx->opts.masterkey_aws_region);
549 bson_free (ctx->opts.masterkey_aws_cmk);
550 bson_free (ctx->opts.masterkey_aws_endpoint);
551 mongocrypt_status_destroy (ctx->status);
552 _mongocrypt_key_broker_cleanup (&ctx->kb);
553 _mongocrypt_key_alt_name_destroy_all (ctx->opts.key_alt_names);
554 _mongocrypt_buffer_cleanup (&ctx->opts.key_id);
555 bson_free (ctx);
556 return;
557 }
558
559
560 bool
mongocrypt_ctx_setopt_masterkey_aws(mongocrypt_ctx_t * ctx,const char * region,int32_t region_len,const char * cmk,int32_t cmk_len)561 mongocrypt_ctx_setopt_masterkey_aws (mongocrypt_ctx_t *ctx,
562 const char *region,
563 int32_t region_len,
564 const char *cmk,
565 int32_t cmk_len)
566 {
567 if (!ctx) {
568 return false;
569 }
570 if (ctx->initialized) {
571 return _mongocrypt_ctx_fail_w_msg (ctx, "cannot set options after init");
572 }
573
574 if (ctx->state == MONGOCRYPT_CTX_ERROR) {
575 return false;
576 }
577
578 if (ctx->opts.masterkey_kms_provider) {
579 return _mongocrypt_ctx_fail_w_msg (ctx, "master key already set");
580 }
581
582 if (!_mongocrypt_validate_and_copy_string (
583 region, region_len, &ctx->opts.masterkey_aws_region) ||
584 region_len == 0) {
585 return _mongocrypt_ctx_fail_w_msg (ctx, "invalid region");
586 }
587
588 if (!_mongocrypt_validate_and_copy_string (
589 cmk, cmk_len, &ctx->opts.masterkey_aws_cmk) ||
590 cmk_len == 0) {
591 return _mongocrypt_ctx_fail_w_msg (ctx, "invalid cmk passed");
592 }
593
594 if (ctx->crypt->log.trace_enabled) {
595 _mongocrypt_log (&ctx->crypt->log,
596 MONGOCRYPT_LOG_LEVEL_TRACE,
597 "%s (%s=\"%s\", %s=%d, %s=\"%s\", %s=%d)",
598 BSON_FUNC,
599 "region",
600 ctx->opts.masterkey_aws_region,
601 "region_len",
602 region_len,
603 "cmk",
604 ctx->opts.masterkey_aws_cmk,
605 "cmk_len",
606 cmk_len);
607 }
608
609 ctx->opts.masterkey_kms_provider = MONGOCRYPT_KMS_PROVIDER_AWS;
610 ctx->opts.masterkey_aws_region_len = region_len;
611 ctx->opts.masterkey_aws_cmk_len = cmk_len;
612 return true;
613 }
614
615
616 bool
mongocrypt_ctx_setopt_masterkey_local(mongocrypt_ctx_t * ctx)617 mongocrypt_ctx_setopt_masterkey_local (mongocrypt_ctx_t *ctx)
618 {
619 if (!ctx) {
620 return false;
621 }
622 if (ctx->initialized) {
623 return _mongocrypt_ctx_fail_w_msg (ctx, "cannot set options after init");
624 }
625
626 if (ctx->state == MONGOCRYPT_CTX_ERROR) {
627 return false;
628 }
629
630 if (ctx->opts.masterkey_kms_provider) {
631 return _mongocrypt_ctx_fail_w_msg (ctx, "master key already set");
632 }
633
634 ctx->opts.masterkey_kms_provider = MONGOCRYPT_KMS_PROVIDER_LOCAL;
635 return true;
636 }
637
638
639 bool
_mongocrypt_ctx_init(mongocrypt_ctx_t * ctx,_mongocrypt_ctx_opts_spec_t * opts_spec)640 _mongocrypt_ctx_init (mongocrypt_ctx_t *ctx,
641 _mongocrypt_ctx_opts_spec_t *opts_spec)
642 {
643 bool has_id = false, has_alt_name = false, has_multiple_alt_names = false;
644
645 if (ctx->initialized) {
646 return _mongocrypt_ctx_fail_w_msg (ctx, "cannot double initialize");
647 }
648 ctx->initialized = true;
649
650 if (ctx->state == MONGOCRYPT_CTX_ERROR) {
651 return false;
652 }
653 /* Set some default functions */
654 ctx->vtable.mongo_op_keys = _mongo_op_keys;
655 ctx->vtable.mongo_feed_keys = _mongo_feed_keys;
656 ctx->vtable.mongo_done_keys = _mongo_done_keys;
657 ctx->vtable.next_kms_ctx = _next_kms_ctx;
658 ctx->vtable.kms_done = _kms_done;
659
660 /* Check that required options are included and prohibited options are
661 * not.
662 */
663
664 if (opts_spec->masterkey == OPT_REQUIRED) {
665 if (!ctx->opts.masterkey_kms_provider) {
666 return _mongocrypt_ctx_fail_w_msg (ctx, "master key required");
667 }
668 if (!(ctx->opts.masterkey_kms_provider &
669 ctx->crypt->opts.kms_providers)) {
670 return _mongocrypt_ctx_fail_w_msg (
671 ctx, "requested kms provider not configured");
672 }
673 }
674
675 if (opts_spec->masterkey == OPT_PROHIBITED &&
676 ctx->opts.masterkey_kms_provider) {
677 return _mongocrypt_ctx_fail_w_msg (ctx, "master key prohibited");
678 }
679
680 /* Special case. key_descriptor applies to explicit encryption. It must be
681 * either a key id or *one* key alt name, but not both.
682 * key_alt_names applies to creating a data key. It may be one or multiple
683 * key alt names.
684 */
685 has_id = !_mongocrypt_buffer_empty (&ctx->opts.key_id);
686 has_alt_name = !!(ctx->opts.key_alt_names);
687 has_multiple_alt_names = has_alt_name && !!(ctx->opts.key_alt_names->next);
688
689 if (opts_spec->key_descriptor == OPT_REQUIRED) {
690 if (!has_id && !has_alt_name) {
691 return _mongocrypt_ctx_fail_w_msg (
692 ctx, "either key id or key alt name required");
693 }
694
695 if (has_id && has_alt_name) {
696 return _mongocrypt_ctx_fail_w_msg (
697 ctx, "cannot have both key id and key alt name");
698 }
699
700 if (has_multiple_alt_names) {
701 return _mongocrypt_ctx_fail_w_msg (
702 ctx, "must not specify multiple key alt names");
703 }
704 }
705
706 if (opts_spec->key_descriptor == OPT_PROHIBITED) {
707 /* still okay if key_alt_names are allowed and only alt names were
708 * specified. */
709 if ((opts_spec->key_alt_names == OPT_PROHIBITED && has_alt_name) ||
710 has_id) {
711 return _mongocrypt_ctx_fail_w_msg (ctx,
712 "key id and alt name prohibited");
713 }
714 }
715
716 if (opts_spec->algorithm == OPT_REQUIRED &&
717 ctx->opts.algorithm == MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE) {
718 return _mongocrypt_ctx_fail_w_msg (ctx, "algorithm required");
719 }
720
721 if (opts_spec->algorithm == OPT_PROHIBITED &&
722 ctx->opts.algorithm != MONGOCRYPT_ENCRYPTION_ALGORITHM_NONE) {
723 return _mongocrypt_ctx_fail_w_msg (ctx, "algorithm prohibited");
724 }
725
726 if (opts_spec->endpoint == OPT_REQUIRED &&
727 !ctx->opts.masterkey_aws_endpoint) {
728 return _mongocrypt_ctx_fail_w_msg (ctx, "endpoint required");
729 }
730
731 if (opts_spec->endpoint == OPT_PROHIBITED &&
732 ctx->opts.masterkey_aws_endpoint) {
733 return _mongocrypt_ctx_fail_w_msg (ctx, "endpoint prohibited");
734 }
735
736 _mongocrypt_key_broker_init (&ctx->kb, ctx->crypt);
737 return true;
738 }
739
740 bool
_mongocrypt_ctx_state_from_key_broker(mongocrypt_ctx_t * ctx)741 _mongocrypt_ctx_state_from_key_broker (mongocrypt_ctx_t *ctx)
742 {
743 _mongocrypt_key_broker_t *kb;
744 mongocrypt_status_t *status;
745 mongocrypt_ctx_state_t new_state = MONGOCRYPT_CTX_ERROR;
746 bool ret = false;
747
748 status = ctx->status;
749 kb = &ctx->kb;
750
751 if (ctx->state == MONGOCRYPT_CTX_ERROR) {
752 return false;
753 }
754
755
756 switch (kb->state) {
757 case KB_ERROR:
758 _mongocrypt_status_copy_to (kb->status, status);
759 new_state = MONGOCRYPT_CTX_ERROR;
760 ret = false;
761 break;
762 case KB_ADDING_DOCS:
763 /* Require key documents from driver. */
764 new_state = MONGOCRYPT_CTX_NEED_MONGO_KEYS;
765 ret = true;
766 break;
767 case KB_DECRYPTING_KEY_MATERIAL:
768 /* Encrypted keys need KMS. */
769 new_state = MONGOCRYPT_CTX_NEED_KMS;
770 ret = true;
771 break;
772 case KB_DONE:
773 new_state = MONGOCRYPT_CTX_READY;
774 if (kb->key_requests == NULL) {
775 /* No key requests were ever added. */
776 ctx->nothing_to_do = true; /* nothing to encrypt/decrypt */
777 }
778 ret = true;
779 break;
780 /* As currently implemented, we do not expect to ever be in KB_REQUESTING
781 * state when calling this function. */
782 case KB_REQUESTING:
783 CLIENT_ERR ("key broker in unexpected state");
784 new_state = MONGOCRYPT_CTX_ERROR;
785 ret = false;
786 break;
787 }
788
789 if (new_state != ctx->state) {
790 ctx->state = new_state;
791 }
792
793 return ret;
794 }
795
796
797 bool
mongocrypt_ctx_setopt_masterkey_aws_endpoint(mongocrypt_ctx_t * ctx,const char * endpoint,int32_t endpoint_len)798 mongocrypt_ctx_setopt_masterkey_aws_endpoint (mongocrypt_ctx_t *ctx,
799 const char *endpoint,
800 int32_t endpoint_len)
801 {
802 if (!ctx) {
803 return false;
804 }
805
806 if (ctx->initialized) {
807 return _mongocrypt_ctx_fail_w_msg (ctx, "cannot set options after init");
808 }
809
810 if (ctx->state == MONGOCRYPT_CTX_ERROR) {
811 return false;
812 }
813
814 if (ctx->opts.masterkey_aws_endpoint) {
815 return _mongocrypt_ctx_fail_w_msg (ctx, "already set masterkey endpoint");
816 }
817
818 if (!_mongocrypt_validate_and_copy_string (
819 endpoint, endpoint_len, &ctx->opts.masterkey_aws_endpoint)) {
820 return _mongocrypt_ctx_fail_w_msg (ctx, "invalid masterkey endpoint");
821 }
822 ctx->opts.masterkey_aws_endpoint_len = endpoint_len;
823 return true;
824 }