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 "mongocrypt-key-broker-private.h"
18 #include "mongocrypt-private.h"
19
20 void
_mongocrypt_key_broker_init(_mongocrypt_key_broker_t * kb,mongocrypt_t * crypt)21 _mongocrypt_key_broker_init (_mongocrypt_key_broker_t *kb, mongocrypt_t *crypt)
22 {
23 memset (kb, 0, sizeof (*kb));
24 kb->crypt = crypt;
25 kb->state = KB_REQUESTING;
26 kb->status = mongocrypt_status_new ();
27 }
28
29 /*
30 * Creates a new key_returned_t and prepends it to a list.
31 *
32 * Side effects:
33 * - updates *list to point to a new head.
34 */
35 static key_returned_t *
_key_returned_prepend(_mongocrypt_key_broker_t * kb,key_returned_t ** list,_mongocrypt_key_doc_t * key_doc)36 _key_returned_prepend (_mongocrypt_key_broker_t *kb,
37 key_returned_t **list,
38 _mongocrypt_key_doc_t *key_doc)
39 {
40 key_returned_t *key_returned;
41
42 BSON_ASSERT (key_doc);
43
44 key_returned = bson_malloc0 (sizeof (*key_returned));
45 BSON_ASSERT (key_returned);
46
47 key_returned->doc = _mongocrypt_key_new ();
48 _mongocrypt_key_doc_copy_to (key_doc, key_returned->doc);
49
50 /* Prepend and update the head of the list. */
51 key_returned->next = *list;
52 *list = key_returned;
53
54 /* Update the head of the decrypting iter. */
55 kb->decryptor_iter = kb->keys_returned;
56 return key_returned;
57 }
58
59 /* Find the first (if any) key_returned_t matching either a key_id or a list of
60 * key_alt_names (both are NULLable) */
61 static key_returned_t *
_key_returned_find_one(key_returned_t * list,_mongocrypt_buffer_t * key_id,_mongocrypt_key_alt_name_t * key_alt_names)62 _key_returned_find_one (key_returned_t *list,
63 _mongocrypt_buffer_t *key_id,
64 _mongocrypt_key_alt_name_t *key_alt_names)
65 {
66 key_returned_t *key_returned;
67
68 for (key_returned = list; NULL != key_returned;
69 key_returned = key_returned->next) {
70 if (key_id) {
71 if (0 == _mongocrypt_buffer_cmp (key_id, &key_returned->doc->id)) {
72 return key_returned;
73 }
74 }
75 if (key_alt_names) {
76 if (_mongocrypt_key_alt_name_intersects (
77 key_alt_names, key_returned->doc->key_alt_names)) {
78 return key_returned;
79 }
80 }
81 }
82
83 return NULL;
84 }
85
86 /* Find the first (if any) key_request_t in the key broker matching either a
87 * key_id or a list of key_alt_names (both are NULLable) */
88 static key_request_t *
_key_request_find_one(_mongocrypt_key_broker_t * kb,const _mongocrypt_buffer_t * key_id,_mongocrypt_key_alt_name_t * key_alt_names)89 _key_request_find_one (_mongocrypt_key_broker_t *kb,
90 const _mongocrypt_buffer_t *key_id,
91 _mongocrypt_key_alt_name_t *key_alt_names)
92 {
93 key_request_t *key_request;
94
95 for (key_request = kb->key_requests; NULL != key_request;
96 key_request = key_request->next) {
97 if (key_id) {
98 if (0 == _mongocrypt_buffer_cmp (key_id, &key_request->id)) {
99 return key_request;
100 }
101 }
102 if (key_alt_names) {
103 if (_mongocrypt_key_alt_name_intersects (key_alt_names,
104 key_request->alt_name)) {
105 return key_request;
106 }
107 }
108 }
109
110 return NULL;
111 }
112
113 static bool
_all_key_requests_satisfied(_mongocrypt_key_broker_t * kb)114 _all_key_requests_satisfied (_mongocrypt_key_broker_t *kb)
115 {
116 key_request_t *key_request;
117
118 for (key_request = kb->key_requests; NULL != key_request;
119 key_request = key_request->next) {
120 if (!key_request->satisfied) {
121 return false;
122 }
123 }
124 return true;
125 }
126
127 static bool
_key_broker_fail_w_msg(_mongocrypt_key_broker_t * kb,const char * msg)128 _key_broker_fail_w_msg (_mongocrypt_key_broker_t *kb, const char *msg)
129 {
130 mongocrypt_status_t *status;
131
132 kb->state = KB_ERROR;
133 status = kb->status;
134 CLIENT_ERR (msg);
135 return false;
136 }
137
138 static bool
_key_broker_fail(_mongocrypt_key_broker_t * kb)139 _key_broker_fail (_mongocrypt_key_broker_t *kb)
140 {
141 if (mongocrypt_status_ok (kb->status)) {
142 return _key_broker_fail_w_msg (
143 kb, "unexpected, failing but no error status set");
144 }
145 kb->state = KB_ERROR;
146 return false;
147 }
148
149 static bool
_try_satisfying_from_cache(_mongocrypt_key_broker_t * kb,key_request_t * req)150 _try_satisfying_from_cache (_mongocrypt_key_broker_t *kb, key_request_t *req)
151 {
152 _mongocrypt_cache_key_attr_t *attr = NULL;
153 _mongocrypt_cache_key_value_t *value = NULL;
154 bool ret = false;
155
156 if (kb->state != KB_REQUESTING) {
157 _key_broker_fail_w_msg (
158 kb, "trying to retrieve key from cache in invalid state");
159 goto cleanup;
160 }
161
162 attr = _mongocrypt_cache_key_attr_new (&req->id, req->alt_name);
163 if (!_mongocrypt_cache_get (&kb->crypt->cache_key, attr, (void **) &value)) {
164 _key_broker_fail_w_msg (kb, "failed to retrieve from cache");
165 goto cleanup;
166 }
167
168 if (value) {
169 key_returned_t *key_returned;
170
171 req->satisfied = true;
172 if (_mongocrypt_buffer_empty (&value->decrypted_key_material)) {
173 _key_broker_fail_w_msg (
174 kb, "cache entry does not have decrypted key material");
175 goto cleanup;
176 }
177
178 /* Add the cached key to our locally copied list.
179 * Note, we deduplicate requests, but *not* keys from the cache,
180 * because the state of the cache may change between each call to
181 * _mongocrypt_cache_get.
182 */
183 key_returned =
184 _key_returned_prepend (kb, &kb->keys_cached, value->key_doc);
185 _mongocrypt_buffer_init (&key_returned->decrypted_key_material);
186 _mongocrypt_buffer_copy_to (&value->decrypted_key_material,
187 &key_returned->decrypted_key_material);
188 key_returned->decrypted = true;
189 }
190
191 ret = true;
192 cleanup:
193 _mongocrypt_cache_key_value_destroy (value);
194 _mongocrypt_cache_key_attr_destroy (attr);
195 return ret;
196 }
197
198 static bool
_store_to_cache(_mongocrypt_key_broker_t * kb,key_returned_t * key_returned)199 _store_to_cache (_mongocrypt_key_broker_t *kb, key_returned_t *key_returned)
200 {
201 _mongocrypt_cache_key_value_t *value;
202 _mongocrypt_cache_key_attr_t *attr;
203 bool ret;
204
205 if (!key_returned->decrypted) {
206 return _key_broker_fail_w_msg (kb, "cannot cache non-decrypted key");
207 }
208
209 attr = _mongocrypt_cache_key_attr_new (&key_returned->doc->id,
210 key_returned->doc->key_alt_names);
211 if (!attr) {
212 return _key_broker_fail_w_msg (kb,
213 "could not create key cache attribute");
214 }
215 value = _mongocrypt_cache_key_value_new (
216 key_returned->doc, &key_returned->decrypted_key_material);
217 ret = _mongocrypt_cache_add_stolen (
218 &kb->crypt->cache_key, attr, value, kb->status);
219 _mongocrypt_cache_key_attr_destroy (attr);
220 if (!ret) {
221 return _key_broker_fail (kb);
222 }
223 return true;
224 }
225
226 bool
_mongocrypt_key_broker_request_id(_mongocrypt_key_broker_t * kb,const _mongocrypt_buffer_t * key_id)227 _mongocrypt_key_broker_request_id (_mongocrypt_key_broker_t *kb,
228 const _mongocrypt_buffer_t *key_id)
229 {
230 key_request_t *req;
231
232 if (kb->state != KB_REQUESTING) {
233 return _key_broker_fail_w_msg (
234 kb, "attempting to request a key id, but in wrong state");
235 }
236
237 if (!_mongocrypt_buffer_is_uuid ((_mongocrypt_buffer_t *) key_id)) {
238 return _key_broker_fail_w_msg (kb, "expected UUID for key id");
239 }
240
241 if (_key_request_find_one (kb, key_id, NULL)) {
242 return true;
243 }
244
245 req = bson_malloc0 (sizeof *req);
246 BSON_ASSERT (req);
247
248 _mongocrypt_buffer_copy_to (key_id, &req->id);
249 req->next = kb->key_requests;
250 kb->key_requests = req;
251 if (!_try_satisfying_from_cache (kb, req)) {
252 return false;
253 }
254 return true;
255 }
256
257
258 bool
_mongocrypt_key_broker_request_name(_mongocrypt_key_broker_t * kb,const bson_value_t * key_alt_name_value)259 _mongocrypt_key_broker_request_name (_mongocrypt_key_broker_t *kb,
260 const bson_value_t *key_alt_name_value)
261 {
262 key_request_t *req;
263 _mongocrypt_key_alt_name_t *key_alt_name;
264
265 if (kb->state != KB_REQUESTING) {
266 return _key_broker_fail_w_msg (
267 kb, "attempting to request a key name, but in wrong state");
268 }
269
270 key_alt_name = _mongocrypt_key_alt_name_new (key_alt_name_value);
271
272 /* Check if we already have a request for this key alt name. */
273 if (_key_request_find_one (kb, NULL /* key id */, key_alt_name)) {
274 _mongocrypt_key_alt_name_destroy_all (key_alt_name);
275 return true;
276 }
277
278 req = bson_malloc0 (sizeof *req);
279 BSON_ASSERT (req);
280
281 req->alt_name = key_alt_name /* takes ownership */;
282 req->next = kb->key_requests;
283 kb->key_requests = req;
284 if (!_try_satisfying_from_cache (kb, req)) {
285 return false;
286 }
287 return true;
288 }
289
290 bool
_mongocrypt_key_broker_requests_done(_mongocrypt_key_broker_t * kb)291 _mongocrypt_key_broker_requests_done (_mongocrypt_key_broker_t *kb)
292 {
293 if (kb->state != KB_REQUESTING) {
294 return _key_broker_fail_w_msg (
295 kb, "attempting to finish adding requests, but in wrong state");
296 }
297
298 if (kb->key_requests) {
299 /* If all were satisfied from the cache, then we're done since those all
300 * have decrypted material */
301 if (_all_key_requests_satisfied (kb)) {
302 kb->state = KB_DONE;
303 } else {
304 kb->state = KB_ADDING_DOCS;
305 }
306 } else {
307 kb->state = KB_DONE;
308 }
309 return true;
310 }
311
312 bool
_mongocrypt_key_broker_filter(_mongocrypt_key_broker_t * kb,mongocrypt_binary_t * out)313 _mongocrypt_key_broker_filter (_mongocrypt_key_broker_t *kb,
314 mongocrypt_binary_t *out)
315 {
316 key_request_t *req;
317 _mongocrypt_key_alt_name_t *key_alt_name;
318 int name_index = 0;
319 int id_index = 0;
320 bson_t ids, names;
321 bson_t *filter;
322
323 BSON_ASSERT (kb);
324
325 if (kb->state != KB_ADDING_DOCS) {
326 return _key_broker_fail_w_msg (
327 kb, "attempting to retrieve filter, but in wrong state");
328 }
329
330 if (!_mongocrypt_buffer_empty (&kb->filter)) {
331 _mongocrypt_buffer_to_binary (&kb->filter, out);
332 return true;
333 }
334
335 bson_init (&names);
336 bson_init (&ids);
337
338 for (req = kb->key_requests; NULL != req; req = req->next) {
339 if (req->satisfied) {
340 continue;
341 }
342
343 if (!_mongocrypt_buffer_empty (&req->id)) {
344 /* Collect key_ids in "ids" */
345 char *key_str;
346
347 key_str = bson_strdup_printf ("%d", id_index++);
348 if (!key_str ||
349 !_mongocrypt_buffer_append (
350 &req->id, &ids, key_str, (uint32_t) strlen (key_str))) {
351 bson_destroy (&ids);
352 bson_destroy (&names);
353 bson_free (key_str);
354 return _key_broker_fail_w_msg (kb, "could not construct id list");
355 }
356
357 bson_free (key_str);
358 }
359
360 /* Collect key alt names in "names" */
361 for (key_alt_name = req->alt_name; NULL != key_alt_name;
362 key_alt_name = key_alt_name->next) {
363 char *key_str;
364
365 key_str = bson_strdup_printf ("%d", name_index++);
366 BSON_ASSERT (key_str);
367 if (!bson_append_value (&names,
368 key_str,
369 (uint32_t) strlen (key_str),
370 &key_alt_name->value)) {
371 bson_destroy (&ids);
372 bson_destroy (&names);
373 bson_free (key_str);
374 return _key_broker_fail_w_msg (
375 kb, "could not construct keyAltName list");
376 }
377
378 bson_free (key_str);
379 }
380 }
381
382 /*
383 * This is our final query:
384 * { $or: [ { _id: { $in : [ids] }},
385 * { keyAltName : { $in : [names] }} ] }
386 */
387 filter = BCON_NEW ("$or",
388 "[",
389 "{",
390 "_id",
391 "{",
392 "$in",
393 BCON_ARRAY (&ids),
394 "}",
395 "}",
396 "{",
397 "keyAltNames",
398 "{",
399 "$in",
400 BCON_ARRAY (&names),
401 "}",
402 "}",
403 "]");
404
405 _mongocrypt_buffer_steal_from_bson (&kb->filter, filter);
406 _mongocrypt_buffer_to_binary (&kb->filter, out);
407 bson_destroy (&ids);
408 bson_destroy (&names);
409
410 return true;
411 }
412
413 static bool
_decrypt_with_local_kms(_mongocrypt_key_broker_t * kb,_mongocrypt_buffer_t * key_material,_mongocrypt_buffer_t * decrypted_key_material)414 _decrypt_with_local_kms (_mongocrypt_key_broker_t *kb,
415 _mongocrypt_buffer_t *key_material,
416 _mongocrypt_buffer_t *decrypted_key_material)
417 {
418 bool crypt_ret;
419 uint32_t bytes_written;
420
421 _mongocrypt_buffer_init (decrypted_key_material);
422 decrypted_key_material->len =
423 _mongocrypt_calculate_plaintext_len (key_material->len);
424 decrypted_key_material->data = bson_malloc (decrypted_key_material->len);
425 BSON_ASSERT (decrypted_key_material->data);
426
427 decrypted_key_material->owned = true;
428
429 crypt_ret = _mongocrypt_do_decryption (kb->crypt->crypto,
430 NULL /* associated data. */,
431 &kb->crypt->opts.kms_local_key,
432 key_material,
433 decrypted_key_material,
434 &bytes_written,
435 kb->status);
436 if (!crypt_ret) {
437 return _key_broker_fail (kb);
438 }
439
440 decrypted_key_material->len = bytes_written;
441
442 if (decrypted_key_material->len != MONGOCRYPT_KEY_LEN) {
443 return _key_broker_fail_w_msg (kb, "decrypted key is incorrect length");
444 }
445 return true;
446 }
447
448 bool
_mongocrypt_key_broker_add_doc(_mongocrypt_key_broker_t * kb,const _mongocrypt_buffer_t * doc)449 _mongocrypt_key_broker_add_doc (_mongocrypt_key_broker_t *kb,
450 const _mongocrypt_buffer_t *doc)
451 {
452 bool ret = false;
453 bson_t doc_bson;
454 _mongocrypt_key_doc_t *key_doc = NULL;
455 key_request_t *key_request;
456 key_returned_t *key_returned;
457 _mongocrypt_kms_provider_t masterkey_provider;
458
459 if (kb->state != KB_ADDING_DOCS) {
460 _key_broker_fail_w_msg (
461 kb, "attempting to add a key doc, but in wrong state");
462 goto done;
463 }
464
465 if (!doc) {
466 _key_broker_fail_w_msg (kb, "invalid key");
467 goto done;
468 }
469
470 /* First, parse the key document. */
471 key_doc = _mongocrypt_key_new ();
472 if (!_mongocrypt_buffer_to_bson (doc, &doc_bson)) {
473 _key_broker_fail_w_msg (kb, "malformed BSON for key document");
474 goto done;
475 }
476
477 if (!_mongocrypt_key_parse_owned (&doc_bson, key_doc, kb->status)) {
478 goto done;
479 }
480
481 /* Ensure that this document matches at least one request. */
482 if (!_key_request_find_one (kb, &key_doc->id, key_doc->key_alt_names)) {
483 _key_broker_fail_w_msg (
484 kb, "unexpected key returned, does not match any requests");
485 goto done;
486 }
487
488 /* Check if there are other keys_returned with intersecting altnames or
489 * equal id. This is an error. Do *not* check cached keys. */
490 if (_key_returned_find_one (
491 kb->keys_returned, &key_doc->id, key_doc->key_alt_names)) {
492 _key_broker_fail_w_msg (
493 kb, "keys returned have duplicate keyAltNames or _id");
494 goto done;
495 }
496
497 key_returned = _key_returned_prepend (kb, &kb->keys_returned, key_doc);
498
499 /* Check that the returned key doc's provider matches. */
500 masterkey_provider = key_doc->masterkey_provider;
501 if (0 == (masterkey_provider & kb->crypt->opts.kms_providers)) {
502 _key_broker_fail_w_msg (
503 kb, "client not configured with KMS provider necessary to decrypt");
504 goto done;
505 }
506
507 /* If the KMS provider is local, decrypt immediately. Otherwise, create the
508 * HTTP KMS request. */
509 if (masterkey_provider == MONGOCRYPT_KMS_PROVIDER_LOCAL) {
510 if (!_decrypt_with_local_kms (kb,
511 &key_returned->doc->key_material,
512 &key_returned->decrypted_key_material)) {
513 goto done;
514 }
515 key_returned->decrypted = true;
516 if (!_store_to_cache (kb, key_returned)) {
517 goto done;
518 }
519 } else if (masterkey_provider == MONGOCRYPT_KMS_PROVIDER_AWS) {
520 if (!_mongocrypt_kms_ctx_init_aws_decrypt (&key_returned->kms,
521 &kb->crypt->opts,
522 key_doc,
523 &kb->crypt->log,
524 kb->crypt->crypto)) {
525 mongocrypt_kms_ctx_status (&key_returned->kms, kb->status);
526 _key_broker_fail (kb);
527 goto done;
528 }
529 } else {
530 _key_broker_fail_w_msg (kb, "unrecognized kms provider");
531 goto done;
532 }
533
534 /* Mark all matching key requests as satisfied. */
535 for (key_request = kb->key_requests; NULL != key_request;
536 key_request = key_request->next) {
537 if (0 == _mongocrypt_buffer_cmp (&key_doc->id, &key_request->id)) {
538 key_request->satisfied = true;
539 }
540 if (_mongocrypt_key_alt_name_intersects (key_doc->key_alt_names,
541 key_request->alt_name)) {
542 key_request->satisfied = true;
543 }
544 }
545
546 ret = true;
547 done:
548 _mongocrypt_key_destroy (key_doc);
549 return ret;
550 }
551
552 bool
_mongocrypt_key_broker_docs_done(_mongocrypt_key_broker_t * kb)553 _mongocrypt_key_broker_docs_done (_mongocrypt_key_broker_t *kb)
554 {
555 key_returned_t *key_returned;
556 bool needs_decryption;
557
558 if (kb->state != KB_ADDING_DOCS) {
559 return _key_broker_fail_w_msg (
560 kb, "attempting to finish adding docs, but in wrong state");
561 }
562
563 /* If there are any requests left unsatisfied, error. */
564 if (!_all_key_requests_satisfied (kb)) {
565 return _key_broker_fail_w_msg (kb,
566 "not all keys requested were satisfied");
567 }
568
569 /* If we're using a local key provider, or every key was retrieved from the
570 * cache, skip the decrypting state. */
571 needs_decryption = false;
572 for (key_returned = kb->keys_returned; NULL != key_returned;
573 key_returned = key_returned->next) {
574 if (!key_returned->decrypted) {
575 needs_decryption = true;
576 break;
577 }
578 }
579
580 if (needs_decryption) {
581 kb->state = KB_DECRYPTING_KEY_MATERIAL;
582 } else {
583 kb->state = KB_DONE;
584 }
585 return true;
586 }
587
588 mongocrypt_kms_ctx_t *
_mongocrypt_key_broker_next_kms(_mongocrypt_key_broker_t * kb)589 _mongocrypt_key_broker_next_kms (_mongocrypt_key_broker_t *kb)
590 {
591 if (kb->state != KB_DECRYPTING_KEY_MATERIAL) {
592 _key_broker_fail_w_msg (
593 kb, "attempting to get KMS request, but in wrong state");
594 /* TODO (CDRIVER-3327) this breaks other expectations. If the caller only
595 * checks the return value they may mistake this NULL as indicating all
596 * KMS requests have been iterated. */
597 return NULL;
598 }
599
600 while (kb->decryptor_iter) {
601 if (!kb->decryptor_iter->decrypted) {
602 key_returned_t *key_returned;
603
604 key_returned = kb->decryptor_iter;
605 /* iterate before returning, so next call starts at next entry */
606 kb->decryptor_iter = kb->decryptor_iter->next;
607 return &key_returned->kms;
608 }
609 kb->decryptor_iter = kb->decryptor_iter->next;
610 }
611
612 return NULL;
613 }
614
615 bool
_mongocrypt_key_broker_kms_done(_mongocrypt_key_broker_t * kb)616 _mongocrypt_key_broker_kms_done (_mongocrypt_key_broker_t *kb)
617 {
618 key_returned_t *key_returned;
619
620 if (kb->state != KB_DECRYPTING_KEY_MATERIAL) {
621 return _key_broker_fail_w_msg (
622 kb, "attempting to complete KMS requests, but in wrong state");
623 }
624
625 for (key_returned = kb->keys_returned; NULL != key_returned;
626 key_returned = key_returned->next) {
627 /* Local keys were already decrypted. */
628 if (key_returned->doc->masterkey_provider ==
629 MONGOCRYPT_KMS_PROVIDER_AWS) {
630 if (key_returned->decrypted) {
631 return _key_broker_fail_w_msg (
632 kb,
633 "unexpected, returned keys should not be "
634 "decrypted before KMS completion");
635 }
636
637 if (!key_returned->kms.req) {
638 return _key_broker_fail_w_msg (
639 kb, "unexpected, KMS not set on key returned");
640 }
641
642 if (!_mongocrypt_kms_ctx_result (
643 &key_returned->kms, &key_returned->decrypted_key_material)) {
644 /* Always fatal. Key attempted to decrypt but failed. */
645 mongocrypt_kms_ctx_status (&key_returned->kms, kb->status);
646 return _key_broker_fail (kb);
647 }
648 }
649
650 if (key_returned->decrypted_key_material.len != MONGOCRYPT_KEY_LEN) {
651 return _key_broker_fail_w_msg (kb,
652 "decrypted key is incorrect length");
653 }
654
655 key_returned->decrypted = true;
656 if (!_store_to_cache (kb, key_returned)) {
657 return false;
658 }
659 }
660
661 kb->state = KB_DONE;
662 return true;
663 }
664
665
666 bool
_get_decrypted_key_material(_mongocrypt_key_broker_t * kb,_mongocrypt_buffer_t * key_id,_mongocrypt_key_alt_name_t * key_alt_name,_mongocrypt_buffer_t * out,_mongocrypt_buffer_t * key_id_out)667 _get_decrypted_key_material (_mongocrypt_key_broker_t *kb,
668 _mongocrypt_buffer_t *key_id,
669 _mongocrypt_key_alt_name_t *key_alt_name,
670 _mongocrypt_buffer_t *out,
671 _mongocrypt_buffer_t *key_id_out)
672 {
673 key_returned_t *key_returned;
674
675 _mongocrypt_buffer_init (out);
676 if (key_id_out) {
677 _mongocrypt_buffer_init (key_id_out);
678 }
679 /* Search both keys_returned and keys_cached. */
680
681 key_returned =
682 _key_returned_find_one (kb->keys_returned, key_id, key_alt_name);
683 if (!key_returned) {
684 /* Try the keys retrieved from the cache. */
685 key_returned =
686 _key_returned_find_one (kb->keys_cached, key_id, key_alt_name);
687 }
688
689 if (!key_returned) {
690 return _key_broker_fail_w_msg (kb, "could not find key");
691 }
692
693 if (!key_returned->decrypted) {
694 return _key_broker_fail_w_msg (kb, "unexpected, key not decrypted");
695 }
696
697 _mongocrypt_buffer_copy_to (&key_returned->decrypted_key_material, out);
698 if (key_id_out) {
699 _mongocrypt_buffer_copy_to (&key_returned->doc->id, key_id_out);
700 }
701 return true;
702 }
703
704 bool
_mongocrypt_key_broker_decrypted_key_by_id(_mongocrypt_key_broker_t * kb,const _mongocrypt_buffer_t * key_id,_mongocrypt_buffer_t * out)705 _mongocrypt_key_broker_decrypted_key_by_id (_mongocrypt_key_broker_t *kb,
706 const _mongocrypt_buffer_t *key_id,
707 _mongocrypt_buffer_t *out)
708 {
709 if (kb->state != KB_DONE) {
710 return _key_broker_fail_w_msg (
711 kb, "attempting retrieve decrypted key material, but in wrong state");
712 }
713 return _get_decrypted_key_material (kb,
714 (_mongocrypt_buffer_t *) key_id,
715 NULL /* key alt name */,
716 out,
717 NULL /* key id out */);
718 }
719
720 bool
_mongocrypt_key_broker_decrypted_key_by_name(_mongocrypt_key_broker_t * kb,const bson_value_t * key_alt_name_value,_mongocrypt_buffer_t * out,_mongocrypt_buffer_t * key_id_out)721 _mongocrypt_key_broker_decrypted_key_by_name (
722 _mongocrypt_key_broker_t *kb,
723 const bson_value_t *key_alt_name_value,
724 _mongocrypt_buffer_t *out,
725 _mongocrypt_buffer_t *key_id_out)
726 {
727 bool ret;
728 _mongocrypt_key_alt_name_t *key_alt_name;
729
730 if (kb->state != KB_DONE) {
731 return _key_broker_fail_w_msg (
732 kb, "attempting retrieve decrypted key material, but in wrong state");
733 }
734
735 key_alt_name = _mongocrypt_key_alt_name_new (key_alt_name_value);
736 ret = _get_decrypted_key_material (kb, NULL, key_alt_name, out, key_id_out);
737 _mongocrypt_key_alt_name_destroy_all (key_alt_name);
738 return ret;
739 }
740
741 bool
_mongocrypt_key_broker_status(_mongocrypt_key_broker_t * kb,mongocrypt_status_t * out)742 _mongocrypt_key_broker_status (_mongocrypt_key_broker_t *kb,
743 mongocrypt_status_t *out)
744 {
745 BSON_ASSERT (kb);
746
747 if (!mongocrypt_status_ok (kb->status)) {
748 _mongocrypt_status_copy_to (kb->status, out);
749 return false;
750 }
751
752 return true;
753 }
754
755
756 static void
_destroy_key_requests(key_request_t * head)757 _destroy_key_requests (key_request_t *head)
758 {
759 key_request_t *tmp;
760
761 while (head) {
762 tmp = head->next;
763
764 _mongocrypt_buffer_cleanup (&head->id);
765 _mongocrypt_key_alt_name_destroy_all (head->alt_name);
766
767 bson_free (head);
768 head = tmp;
769 }
770 }
771
772 static void
_destroy_keys_returned(key_returned_t * head)773 _destroy_keys_returned (key_returned_t *head)
774 {
775 key_returned_t *tmp;
776
777 while (head) {
778 tmp = head->next;
779
780 _mongocrypt_key_destroy (head->doc);
781 _mongocrypt_buffer_cleanup (&head->decrypted_key_material);
782 _mongocrypt_kms_ctx_cleanup (&head->kms);
783
784 bson_free (head);
785 head = tmp;
786 }
787 }
788
789 void
_mongocrypt_key_broker_cleanup(_mongocrypt_key_broker_t * kb)790 _mongocrypt_key_broker_cleanup (_mongocrypt_key_broker_t *kb)
791 {
792 mongocrypt_status_destroy (kb->status);
793 _mongocrypt_buffer_cleanup (&kb->filter);
794 /* Delete all linked lists */
795 _destroy_keys_returned (kb->keys_returned);
796 _destroy_keys_returned (kb->keys_cached);
797 _destroy_key_requests (kb->key_requests);
798 }
799
800 void
_mongocrypt_key_broker_add_test_key(_mongocrypt_key_broker_t * kb,const _mongocrypt_buffer_t * key_id)801 _mongocrypt_key_broker_add_test_key (_mongocrypt_key_broker_t *kb,
802 const _mongocrypt_buffer_t *key_id)
803 {
804 key_returned_t *key_returned;
805 _mongocrypt_key_doc_t *key_doc;
806
807 BSON_ASSERT (kb);
808 key_doc = _mongocrypt_key_new ();
809 _mongocrypt_buffer_copy_to (key_id, &key_doc->id);
810
811 key_returned = _key_returned_prepend (kb, &kb->keys_returned, key_doc);
812 key_returned->decrypted = true;
813 _mongocrypt_buffer_init (&key_returned->decrypted_key_material);
814 _mongocrypt_buffer_resize (&key_returned->decrypted_key_material,
815 MONGOCRYPT_KEY_LEN);
816 memset (key_returned->decrypted_key_material.data, 0, MONGOCRYPT_KEY_LEN);
817 _mongocrypt_key_destroy (key_doc);
818 /* Hijack state and move directly to DONE. */
819 kb->state = KB_DONE;
820 }