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 }