/* * Copyright 2022-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. */ #include "test-mongocrypt.h" /* Test authentication with the "gcp" KMS provider. */ static void _test_createdatakey_with_credentials(_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_kms_ctx_t *kms; const char *kek = "{" "'provider': 'gcp'," "'projectId': 'test-projectId'," "'location': 'test-location'," "'keyRing': 'test-keyRing'," "'keyName': 'test-keyName'" "}"; crypt = _mongocrypt_tester_mongocrypt(TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new(crypt); ASSERT_OK(mongocrypt_ctx_setopt_key_encryption_key(ctx, TEST_BSON(kek)), ctx); ASSERT_OK(mongocrypt_ctx_datakey_init(ctx), ctx); ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_NEED_KMS); /* Assert first CTX_NEED_KMS state requests access token. */ { kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(kms, "expected KMS context, got NULL"); const char *endpoint; mongocrypt_kms_ctx_endpoint(kms, &endpoint); ASSERT_STREQUAL("oauth2.googleapis.com:443", endpoint); /* Satisfy request. */ ASSERT_OK(mongocrypt_kms_ctx_feed(kms, TEST_FILE("./test/data/gcp-auth/oauth-response.txt")), kms); ASSERT_CMPINT((int)mongocrypt_kms_ctx_bytes_needed(kms), ==, 0); kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(NULL == kms, "expected NULL KMS context, got non-NULL"); ASSERT_OK(mongocrypt_ctx_kms_done(ctx), ctx); } /* Assert second CTX_NEED_KMS state requests encryption. */ { kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(kms, "expected KMS context, got NULL"); const char *endpoint; mongocrypt_kms_ctx_endpoint(kms, &endpoint); ASSERT_STREQUAL("cloudkms.googleapis.com:443", endpoint); /* Satisfy request. */ ASSERT_OK(mongocrypt_kms_ctx_feed(kms, TEST_FILE("./test/data/gcp-auth/encrypt-response.txt")), kms); ASSERT_CMPINT((int)mongocrypt_kms_ctx_bytes_needed(kms), ==, 0); kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(NULL == kms, "expected NULL KMS context, got non-NULL"); ASSERT_OK(mongocrypt_ctx_kms_done(ctx), ctx); } ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_READY); mongocrypt_ctx_destroy(ctx); mongocrypt_destroy(crypt); } static void _test_encrypt_with_credentials(_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_kms_ctx_t *kms; mongocrypt_binary_t *uuid; const char *uuid_data = "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61"; crypt = _mongocrypt_tester_mongocrypt(TESTER_MONGOCRYPT_DEFAULT); ctx = mongocrypt_ctx_new(crypt); uuid = mongocrypt_binary_new_from_data((uint8_t *)uuid_data, UUID_LEN); ASSERT_OK(mongocrypt_ctx_setopt_key_id(ctx, uuid), ctx); ASSERT_OK(mongocrypt_ctx_setopt_algorithm(ctx, MONGOCRYPT_ALGORITHM_DETERMINISTIC_STR, -1), ctx); ASSERT_OK(mongocrypt_ctx_explicit_encrypt_init(ctx, TEST_BSON("{'v': 1}")), ctx); ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK(mongocrypt_ctx_mongo_feed(ctx, TEST_FILE("./test/data/key-document-gcp.json")), ctx); ASSERT_OK(mongocrypt_ctx_mongo_done(ctx), ctx); } ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_NEED_KMS); /* Assert first CTX_NEED_KMS state requests access token. */ { kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(kms, "expected KMS context, got NULL"); const char *endpoint; mongocrypt_kms_ctx_endpoint(kms, &endpoint); ASSERT_STREQUAL("oauth2.googleapis.com:443", endpoint); /* Satisfy request. */ ASSERT_OK(mongocrypt_kms_ctx_feed(kms, TEST_FILE("./test/data/gcp-auth/oauth-response.txt")), kms); ASSERT_CMPINT((int)mongocrypt_kms_ctx_bytes_needed(kms), ==, 0); kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(NULL == kms, "expected NULL KMS context, got non-NULL"); ASSERT_OK(mongocrypt_ctx_kms_done(ctx), ctx); } /* Assert second CTX_NEED_KMS state requests decryption. */ { kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(kms, "expected KMS context, got NULL"); const char *endpoint; mongocrypt_kms_ctx_endpoint(kms, &endpoint); ASSERT_STREQUAL("cloudkms.googleapis.com:443", endpoint); /* Satisfy request. */ ASSERT_OK(mongocrypt_kms_ctx_feed(kms, TEST_FILE("./test/data/gcp-auth/decrypt-response.txt")), kms); ASSERT_CMPINT((int)mongocrypt_kms_ctx_bytes_needed(kms), ==, 0); kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(NULL == kms, "expected NULL KMS context, got non-NULL"); ASSERT_OK(mongocrypt_ctx_kms_done(ctx), ctx); } ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_READY); mongocrypt_binary_destroy(uuid); mongocrypt_ctx_destroy(ctx); mongocrypt_destroy(crypt); } static void _test_createdatakey_with_accesstoken(_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_kms_ctx_t *kms; const char *kek = "{" "'provider': 'gcp'," "'projectId': 'test-projectId'," "'location': 'test-location'," "'keyRing': 'test-keyRing'," "'keyName': 'test-keyName'" "}"; crypt = mongocrypt_new(); ASSERT_OK(mongocrypt_setopt_kms_providers(crypt, TEST_BSON("{'gcp': {}}")), crypt); mongocrypt_setopt_use_need_kms_credentials_state(crypt); ASSERT_OK(mongocrypt_init(crypt), crypt); ctx = mongocrypt_ctx_new(crypt); ASSERT_OK(mongocrypt_ctx_setopt_key_encryption_key(ctx, TEST_BSON(kek)), ctx); ASSERT_OK(mongocrypt_ctx_datakey_init(ctx), ctx); ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS); { ASSERT_OK(mongocrypt_ctx_provide_kms_providers(ctx, TEST_BSON("{'gcp': { 'accessToken': 'foobar' } }")), ctx); } /* Assert first CTX_NEED_KMS state requests encryption. */ { kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(kms, "expected KMS context, got NULL"); const char *endpoint; mongocrypt_kms_ctx_endpoint(kms, &endpoint); ASSERT_STREQUAL("cloudkms.googleapis.com:443", endpoint); /* Satisfy request. */ ASSERT_OK(mongocrypt_kms_ctx_feed(kms, TEST_FILE("./test/data/gcp-auth/encrypt-response.txt")), kms); ASSERT_CMPINT((int)mongocrypt_kms_ctx_bytes_needed(kms), ==, 0); kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(NULL == kms, "expected NULL KMS context, got non-NULL"); ASSERT_OK(mongocrypt_ctx_kms_done(ctx), ctx); } ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_READY); mongocrypt_ctx_destroy(ctx); mongocrypt_destroy(crypt); } static void _test_encrypt_with_accesstoken(_mongocrypt_tester_t *tester) { mongocrypt_t *crypt; mongocrypt_ctx_t *ctx; mongocrypt_kms_ctx_t *kms; mongocrypt_binary_t *uuid; const char *uuid_data = "\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61"; crypt = mongocrypt_new(); ASSERT_OK(mongocrypt_setopt_kms_providers(crypt, TEST_BSON("{'gcp': {}}")), crypt); mongocrypt_setopt_use_need_kms_credentials_state(crypt); ASSERT_OK(mongocrypt_init(crypt), crypt); ctx = mongocrypt_ctx_new(crypt); uuid = mongocrypt_binary_new_from_data((uint8_t *)uuid_data, UUID_LEN); ASSERT_OK(mongocrypt_ctx_setopt_key_id(ctx, uuid), ctx); ASSERT_OK(mongocrypt_ctx_setopt_algorithm(ctx, MONGOCRYPT_ALGORITHM_DETERMINISTIC_STR, -1), ctx); ASSERT_OK(mongocrypt_ctx_explicit_encrypt_init(ctx, TEST_BSON("{'v': 1}")), ctx); ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_NEED_KMS_CREDENTIALS); { ASSERT_OK(mongocrypt_ctx_provide_kms_providers(ctx, TEST_BSON("{'gcp': { 'accessToken': 'foobar' } }")), ctx); } ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_NEED_MONGO_KEYS); { ASSERT_OK(mongocrypt_ctx_mongo_feed(ctx, TEST_FILE("./test/data/key-document-gcp.json")), ctx); ASSERT_OK(mongocrypt_ctx_mongo_done(ctx), ctx); } ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_NEED_KMS); /* Assert first CTX_NEED_KMS state requests decryption. */ { kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(kms, "expected KMS context, got NULL"); const char *endpoint; mongocrypt_kms_ctx_endpoint(kms, &endpoint); ASSERT_STREQUAL("cloudkms.googleapis.com:443", endpoint); /* Satisfy request. */ ASSERT_OK(mongocrypt_kms_ctx_feed(kms, TEST_FILE("./test/data/gcp-auth/decrypt-response.txt")), kms); ASSERT_CMPINT((int)mongocrypt_kms_ctx_bytes_needed(kms), ==, 0); kms = mongocrypt_ctx_next_kms_ctx(ctx); ASSERT_OR_PRINT_MSG(NULL == kms, "expected NULL KMS context, got non-NULL"); ASSERT_OK(mongocrypt_ctx_kms_done(ctx), ctx); } ASSERT_STATE_EQUAL(mongocrypt_ctx_state(ctx), MONGOCRYPT_CTX_READY); mongocrypt_binary_destroy(uuid); mongocrypt_ctx_destroy(ctx); mongocrypt_destroy(crypt); } void _mongocrypt_tester_install_gcp_auth(_mongocrypt_tester_t *tester) { INSTALL_TEST(_test_createdatakey_with_credentials); INSTALL_TEST(_test_encrypt_with_credentials); INSTALL_TEST(_test_createdatakey_with_accesstoken); INSTALL_TEST(_test_encrypt_with_accesstoken); }