/* * Copyright 2019-present MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* For each field, check a valid value, invalid value, missing value */ #include "bson/bson.h" #include "test-mongocrypt.h" /* Create a basis key document, but exclude some fields. */ static void _recreate_excluding (_mongocrypt_tester_t *tester, bson_t *out, va_list args) { bson_t tmp; BSON_ASSERT (_mongocrypt_binary_to_bson ( TEST_FILE ("./test/data/key-document-full.json"), &tmp)); /* copy to out */ bson_destroy (out); bson_init (out); bson_copy_to_excluding_noinit_va (&tmp, out, "", args); } static void _recreate_and_reset (_mongocrypt_tester_t *tester, bson_t *key_bson, mongocrypt_status_t *status, ...) { va_list args; va_start (args, status); _recreate_excluding (tester, key_bson, args); va_end (args); _mongocrypt_status_reset (status); } static void _parse_ok (bson_t *key_bson, mongocrypt_status_t *status) { _mongocrypt_key_doc_t *key_doc = _mongocrypt_key_new (); ASSERT_OK_STATUS (_mongocrypt_key_parse_owned (key_bson, key_doc, status), status); _mongocrypt_key_destroy (key_doc); } static void _parse_fails (bson_t *key_bson, mongocrypt_status_t *status, const char *msg) { _mongocrypt_key_doc_t *key_doc = _mongocrypt_key_new (); ASSERT_FAILS_STATUS ( _mongocrypt_key_parse_owned (key_bson, key_doc, status), status, msg); _mongocrypt_key_destroy (key_doc); } static void test_mongocrypt_key_parsing (_mongocrypt_tester_t *tester) { bson_t key_bson = BSON_INITIALIZER; mongocrypt_status_t *status; mongocrypt_binary_t *uuid; uuid = TEST_BIN (16); status = mongocrypt_status_new (); /* successful case. */ _recreate_and_reset (tester, &key_bson, status, NULL); _parse_ok (&key_bson, status); /* unrecognized fields */ _recreate_and_reset (tester, &key_bson, status, NULL); BSON_APPEND_INT32 (&key_bson, "invalid", 123); _parse_fails (&key_bson, status, "unrecognized field 'invalid'"); /* malformed BSON */ _recreate_and_reset (tester, &key_bson, status, NULL); /* mess with the length to corrupt the BSON. */ ((uint8_t *) bson_get_data (&key_bson))[4] = 0xFF; _parse_fails (&key_bson, status, "invalid BSON"); /* _id: missing. */ _recreate_and_reset (tester, &key_bson, status, "_id", NULL); _parse_fails (&key_bson, status, "invalid key, no '_id'"); /* _id: wrong type. */ _recreate_and_reset (tester, &key_bson, status, "_id", NULL); BSON_APPEND_INT32 (&key_bson, "_id", 123); _parse_fails (&key_bson, status, "invalid key, '_id' is not a UUID"); /* _id: invalid binary subtype. */ _recreate_and_reset (tester, &key_bson, status, "_id", NULL); BSON_APPEND_BINARY ( &key_bson, "_id", BSON_SUBTYPE_BINARY, uuid->data, uuid->len); _parse_fails (&key_bson, status, "invalid key, '_id' is not a UUID"); /* _id: invalid UUID length. */ _recreate_and_reset (tester, &key_bson, status, "_id", NULL); BSON_APPEND_BINARY (&key_bson, "_id", BSON_SUBTYPE_UUID, uuid->data, 5); _parse_fails (&key_bson, status, "invalid key, '_id' is not a UUID"); /* version: missing (ok) */ _recreate_and_reset (tester, &key_bson, status, "version", NULL); _parse_ok (&key_bson, status); /* version: wrong type */ _recreate_and_reset (tester, &key_bson, status, "version", NULL); BSON_APPEND_UTF8 (&key_bson, "version", "abc"); _parse_fails (&key_bson, status, "invalid 'version'"); /* version: > 0 */ _recreate_and_reset (tester, &key_bson, status, "version", NULL); BSON_APPEND_INT32 (&key_bson, "version", 1); _parse_fails (&key_bson, status, "unsupported key document version"); /* keyMaterial: missing. */ _recreate_and_reset (tester, &key_bson, status, "keyMaterial", NULL); _parse_fails (&key_bson, status, "invalid key, no 'keyMaterial'"); /* keyMaterial: wrong type. */ _recreate_and_reset (tester, &key_bson, status, "keyMaterial", NULL); BSON_APPEND_INT32 (&key_bson, "keyMaterial", 1); _parse_fails (&key_bson, status, "invalid 'keyMaterial', expected binary"); /* keyMaterial: wrong subtype. */ _recreate_and_reset (tester, &key_bson, status, "keyMaterial", NULL); BSON_APPEND_BINARY ( &key_bson, "keyMaterial", BSON_SUBTYPE_UUID, uuid->data, uuid->len); _parse_fails ( &key_bson, status, "invalid 'keyMaterial', expected subtype 0"); /* masterKey: missing. */ _recreate_and_reset (tester, &key_bson, status, "masterKey", NULL); _parse_fails (&key_bson, status, "invalid key, no 'masterKey'"); /* masterKey: missing provider. */ _recreate_and_reset (tester, &key_bson, status, "masterKey", NULL); bson_concat (&key_bson, TMP_BSON ("{'masterKey': { }}")); _parse_fails (&key_bson, status, "expected UTF-8 provider"); /* masterKey: wrong provider. */ _recreate_and_reset (tester, &key_bson, status, "masterKey", NULL); bson_concat (&key_bson, TMP_BSON ("{'masterKey': { 'provider': 'bad' }}")); _parse_fails (&key_bson, status, "unrecognized KMS provider"); /* masterKey: provider=aws, missing key */ _recreate_and_reset (tester, &key_bson, status, "masterKey", NULL); bson_concat ( &key_bson, TMP_BSON ("{'masterKey': { 'provider': 'aws', 'region': 'us-east-1' }}")); _parse_fails (&key_bson, status, "expected UTF-8 key"); /* masterKey: provider=aws, missing region */ _recreate_and_reset (tester, &key_bson, status, "masterKey", NULL); bson_concat ( &key_bson, TMP_BSON ("{'masterKey': { 'provider': 'aws', 'key': 'cmk-string' }}")); _parse_fails (&key_bson, status, "expected UTF-8 region"); /* masterKey: provider=aws, bad region */ _recreate_and_reset (tester, &key_bson, status, "masterKey", NULL); bson_concat (&key_bson, TMP_BSON ("{'masterKey': { 'provider': 'aws', " "'key': 'cmk-string', 'region': 1 }}")); _parse_fails (&key_bson, status, "expected UTF-8 region"); /* creationDate: missing */ _recreate_and_reset (tester, &key_bson, status, "creationDate", NULL); _parse_fails (&key_bson, status, "invalid key, no 'creationDate'"); /* creationDate: wrong type */ _recreate_and_reset (tester, &key_bson, status, "creationDate", NULL); BSON_APPEND_UTF8 (&key_bson, "creationDate", "abc"); _parse_fails (&key_bson, status, "invalid 'creationDate', expect datetime"); /* updateDate: missing */ _recreate_and_reset (tester, &key_bson, status, "updateDate", NULL); _parse_fails (&key_bson, status, "invalid key, no 'updateDate'"); /* updateDate: wrong type */ _recreate_and_reset (tester, &key_bson, status, "updateDate", NULL); BSON_APPEND_UTF8 (&key_bson, "updateDate", "abc"); _parse_fails (&key_bson, status, "invalid 'updateDate', expect datetime"); /* status: missing */ _recreate_and_reset (tester, &key_bson, status, "status", NULL); _parse_fails (&key_bson, status, "invalid key, no 'status'"); /* masterKey: azure */ _recreate_and_reset (tester, &key_bson, status, "masterKey", NULL); bson_concat ( &key_bson, TMP_BSON ( "{'masterKey': { 'provider': 'azure', 'keyVaultEndpoint': " "'abc.example.com', 'keyName': 'test', 'keyVersion': 'abc' }}")); _parse_ok (&key_bson, status); /* masterKey: gcp */ _recreate_and_reset (tester, &key_bson, status, "masterKey", NULL); bson_concat ( &key_bson, TMP_BSON ("{'masterKey': { 'provider': 'gcp', 'endpoint': " "'abc.example.com', 'projectId': 'project', 'location': " "'global', 'keyRing': 'ring', 'keyName': 'name' }}")); _parse_ok (&key_bson, status); mongocrypt_status_destroy (status); bson_destroy (&key_bson); } static void test_mongocrypt_key_alt_name_from_iter (_mongocrypt_tester_t *tester) { mongocrypt_status_t *status; bson_iter_t iter; bson_t *test; _mongocrypt_key_alt_name_t *key_alt_names; status = mongocrypt_status_new (); /* Empty alt names */ test = TMP_BSON ("{'test': []}"); bson_iter_init_find (&iter, test, "test"); ASSERT_OK_STATUS ( _mongocrypt_key_alt_name_from_iter (&iter, &key_alt_names, status), status); BSON_ASSERT (NULL == key_alt_names); /* One alt name */ test = TMP_BSON ("{'test': ['a']}"); bson_iter_init_find (&iter, test, "test"); ASSERT_OK_STATUS ( _mongocrypt_key_alt_name_from_iter (&iter, &key_alt_names, status), status); BSON_ASSERT ( 0 == strcmp ("a", _mongocrypt_key_alt_name_get_string (key_alt_names))); BSON_ASSERT (NULL == key_alt_names->next); _mongocrypt_key_alt_name_destroy_all (key_alt_names); /* Two alt names */ test = TMP_BSON ("{'test': ['a', 'b']}"); bson_iter_init_find (&iter, test, "test"); ASSERT_OK_STATUS ( _mongocrypt_key_alt_name_from_iter (&iter, &key_alt_names, status), status); BSON_ASSERT ( 0 == strcmp ("b", _mongocrypt_key_alt_name_get_string (key_alt_names))); BSON_ASSERT ( 0 == strcmp ("a", _mongocrypt_key_alt_name_get_string (key_alt_names->next))); BSON_ASSERT (NULL == key_alt_names->next->next); _mongocrypt_key_alt_name_destroy_all (key_alt_names); /* Invalid alt names */ test = TMP_BSON ("{'test': ['a', 1]}"); bson_iter_init_find (&iter, test, "test"); ASSERT_FAILS_STATUS ( _mongocrypt_key_alt_name_from_iter (&iter, &key_alt_names, status), status, "unexpected non-UTF8"); /* Duplicate alt names */ test = TMP_BSON ("{'test': ['b', 'a', 'c', 'a']}"); bson_iter_init_find (&iter, test, "test"); ASSERT_FAILS_STATUS ( _mongocrypt_key_alt_name_from_iter (&iter, &key_alt_names, status), status, "duplicate"); mongocrypt_status_destroy (status); } void _mongocrypt_tester_install_key (_mongocrypt_tester_t *tester) { INSTALL_TEST (test_mongocrypt_key_parsing); INSTALL_TEST (test_mongocrypt_key_alt_name_from_iter); }