ext/libmongocrypt/libmongocrypt/src/mongocrypt-kms-ctx.c in libmongocrypt-helper-1.8.0.0.1001 vs ext/libmongocrypt/libmongocrypt/src/mongocrypt-kms-ctx.c in libmongocrypt-helper-1.11.0.0.1001

- old
+ new

@@ -12,14 +12,18 @@ * 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 "kms_message/kms_kmip_request.h" #include "mongocrypt-binary-private.h" #include "mongocrypt-buffer-private.h" +#include "mongocrypt-crypto-private.h" #include "mongocrypt-ctx-private.h" +#include "mongocrypt-endpoint-private.h" #include "mongocrypt-kms-ctx-private.h" +#include "mongocrypt-log-private.h" #include "mongocrypt-opts-private.h" #include "mongocrypt-private.h" #include "mongocrypt-status-private.h" #include "mongocrypt-util-private.h" #include "mongocrypt.h" @@ -116,16 +120,21 @@ } } static bool is_kms(_kms_request_type_t kms_type) { return kms_type == MONGOCRYPT_KMS_KMIP_REGISTER || kms_type == MONGOCRYPT_KMS_KMIP_ACTIVATE - || kms_type == MONGOCRYPT_KMS_KMIP_GET; + || kms_type == MONGOCRYPT_KMS_KMIP_GET || kms_type == MONGOCRYPT_KMS_KMIP_ENCRYPT + || kms_type == MONGOCRYPT_KMS_KMIP_DECRYPT || kms_type == MONGOCRYPT_KMS_KMIP_CREATE; } -static void _init_common(mongocrypt_kms_ctx_t *kms, _mongocrypt_log_t *log, _kms_request_type_t kms_type) { +static void +_init_common(mongocrypt_kms_ctx_t *kms, _mongocrypt_log_t *log, _kms_request_type_t kms_type, const char *kmsid) { BSON_ASSERT_PARAM(kms); + BSON_ASSERT_PARAM(kmsid); + kms->kmsid = bson_strdup(kmsid); + if (is_kms(kms_type)) { kms->parser = kms_kmip_response_parser_new(NULL /* reserved */); } else { kms->parser = kms_response_parser_new(); } @@ -136,23 +145,24 @@ } bool _mongocrypt_kms_ctx_init_aws_decrypt(mongocrypt_kms_ctx_t *kms, _mongocrypt_opts_kms_providers_t *kms_providers, _mongocrypt_key_doc_t *key, - _mongocrypt_log_t *log, - _mongocrypt_crypto_t *crypto) { + _mongocrypt_crypto_t *crypto, + const char *kmsid, + _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms); BSON_ASSERT_PARAM(key); BSON_ASSERT_PARAM(kms_providers); BSON_ASSERT_PARAM(crypto); kms_request_opt_t *opt; mongocrypt_status_t *status; ctx_with_status_t ctx_with_status; bool ret = false; - _init_common(kms, log, MONGOCRYPT_KMS_AWS_DECRYPT); + _init_common(kms, log, MONGOCRYPT_KMS_AWS_DECRYPT, kmsid); status = kms->status; ctx_with_status.ctx = crypto; ctx_with_status.status = mongocrypt_status_new(); if (!key->kek.kms_provider) { @@ -168,21 +178,23 @@ if (!key->kek.provider.aws.region) { CLIENT_ERR("no key region provided"); goto done; } - if (0 == (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_AWS)) { - CLIENT_ERR("aws kms not configured"); + mc_kms_creds_t kc; + if (!_mongocrypt_opts_kms_providers_lookup(kms_providers, key->kek.kmsid, &kc)) { + CLIENT_ERR("KMS provider `%s` is not configured", key->kek.kmsid); goto done; } + BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_AWS); - if (!kms_providers->aws.access_key_id) { + if (!kc.value.aws.access_key_id) { CLIENT_ERR("aws access key id not provided"); goto done; } - if (!kms_providers->aws.secret_access_key) { + if (!kc.value.aws.secret_access_key) { CLIENT_ERR("aws secret access key not provided"); goto done; } /* create the KMS request. */ @@ -199,12 +211,12 @@ CLIENT_ERR("failed to set service: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto done; } - if (kms_providers->aws.session_token) { - if (!kms_request_add_header_field(kms->req, "X-Amz-Security-Token", kms_providers->aws.session_token)) { + if (kc.value.aws.session_token) { + if (!kms_request_add_header_field(kms->req, "X-Amz-Security-Token", kc.value.aws.session_token)) { CLIENT_ERR("failed to set session token: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto done; } } @@ -228,16 +240,16 @@ CLIENT_ERR("failed to set region: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto done; } - if (!kms_request_set_access_key_id(kms->req, kms_providers->aws.access_key_id)) { + if (!kms_request_set_access_key_id(kms->req, kc.value.aws.access_key_id)) { CLIENT_ERR("failed to set aws access key id: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto done; } - if (!kms_request_set_secret_key(kms->req, kms_providers->aws.secret_access_key)) { + if (!kms_request_set_secret_key(kms->req, kc.value.aws.secret_access_key)) { CLIENT_ERR("failed to set aws secret access key: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto done; } @@ -268,12 +280,13 @@ bool _mongocrypt_kms_ctx_init_aws_encrypt(mongocrypt_kms_ctx_t *kms, _mongocrypt_opts_kms_providers_t *kms_providers, _mongocrypt_ctx_opts_t *ctx_opts, _mongocrypt_buffer_t *plaintext_key_material, - _mongocrypt_log_t *log, - _mongocrypt_crypto_t *crypto) { + _mongocrypt_crypto_t *crypto, + const char *kmsid, + _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms); BSON_ASSERT_PARAM(ctx_opts); BSON_ASSERT_PARAM(kms_providers); BSON_ASSERT_PARAM(crypto); BSON_ASSERT_PARAM(plaintext_key_material); @@ -281,11 +294,11 @@ kms_request_opt_t *opt; mongocrypt_status_t *status; ctx_with_status_t ctx_with_status; bool ret = false; - _init_common(kms, log, MONGOCRYPT_KMS_AWS_ENCRYPT); + _init_common(kms, log, MONGOCRYPT_KMS_AWS_ENCRYPT, kmsid); status = kms->status; ctx_with_status.ctx = crypto; ctx_with_status.status = mongocrypt_status_new(); if (MONGOCRYPT_KMS_PROVIDER_AWS != ctx_opts->kek.kms_provider) { @@ -301,21 +314,23 @@ if (!ctx_opts->kek.provider.aws.cmk) { CLIENT_ERR("no aws cmk provided"); goto done; } - if (0 == (kms_providers->configured_providers & MONGOCRYPT_KMS_PROVIDER_AWS)) { - CLIENT_ERR("aws kms not configured"); + mc_kms_creds_t kc; + if (!_mongocrypt_opts_kms_providers_lookup(kms_providers, ctx_opts->kek.kmsid, &kc)) { + CLIENT_ERR("KMS provider `%s` is not configured", ctx_opts->kek.kmsid); goto done; } + BSON_ASSERT(kc.type == MONGOCRYPT_KMS_PROVIDER_AWS); - if (!kms_providers->aws.access_key_id) { + if (!kc.value.aws.access_key_id) { CLIENT_ERR("aws access key id not provided"); goto done; } - if (!kms_providers->aws.secret_access_key) { + if (!kc.value.aws.secret_access_key) { CLIENT_ERR("aws secret access key not provided"); goto done; } /* create the KMS request. */ @@ -335,12 +350,12 @@ CLIENT_ERR("failed to set service: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto done; } - if (kms_providers->aws.session_token) { - if (!kms_request_add_header_field(kms->req, "X-Amz-Security-Token", kms_providers->aws.session_token)) { + if (kc.value.aws.session_token) { + if (!kms_request_add_header_field(kms->req, "X-Amz-Security-Token", kc.value.aws.session_token)) { CLIENT_ERR("failed to set session token: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto done; } } @@ -364,16 +379,16 @@ CLIENT_ERR("failed to set region: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto done; } - if (!kms_request_set_access_key_id(kms->req, kms_providers->aws.access_key_id)) { + if (!kms_request_set_access_key_id(kms->req, kc.value.aws.access_key_id)) { CLIENT_ERR("failed to set aws access key id: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto done; } - if (!kms_request_set_secret_key(kms->req, kms_providers->aws.secret_access_key)) { + if (!kms_request_set_secret_key(kms->req, kc.value.aws.secret_access_key)) { CLIENT_ERR("failed to set aws secret access key: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto done; } @@ -462,10 +477,14 @@ status = kms->status; ret = false; /* Parse out the {en|de}crypted result. */ http_status = kms_response_parser_status(kms->parser); response = kms_response_parser_get_response(kms->parser); + if (!response) { + CLIENT_ERR("Failed to get response from parser: %s", kms_response_parser_error(kms->parser)); + goto fail; + } body = kms_response_get_body(response, &body_len); if (http_status != 200) { _handle_non200_http_status(http_status, body, body_len, status); goto fail; @@ -539,10 +558,14 @@ status = kms->status; ret = false; /* Parse out the oauth token result (or error). */ http_status = kms_response_parser_status(kms->parser); response = kms_response_parser_get_response(kms->parser); + if (!response) { + CLIENT_ERR("Failed to get response from parser: %s", kms_response_parser_error(kms->parser)); + goto fail; + } body = kms_response_get_body(response, &body_len); if (body_len == 0) { CLIENT_ERR("Empty KMS response. HTTP status=%d", http_status); goto fail; @@ -612,10 +635,14 @@ status = kms->status; ret = false; /* Parse out the oauth token result (or error). */ http_status = kms_response_parser_status(kms->parser); response = kms_response_parser_get_response(kms->parser); + if (!response) { + CLIENT_ERR("Failed to get response from parser: %s", kms_response_parser_error(kms->parser)); + goto fail; + } body = kms_response_get_body(response, &body_len); if (body_len == 0) { CLIENT_ERR("Empty KMS response. HTTP status=%d", http_status); goto fail; @@ -702,10 +729,14 @@ status = kms->status; ret = false; /* Parse out the {en|de}crypted result. */ http_status = kms_response_parser_status(kms->parser); response = kms_response_parser_get_response(kms->parser); + if (!response) { + CLIENT_ERR("Failed to get response from parser: %s", kms_response_parser_error(kms->parser)); + goto fail; + } body = kms_response_get_body(response, &body_len); if (http_status != 200) { _handle_non200_http_status(http_status, body, body_len, status); goto fail; @@ -824,10 +855,148 @@ done: kms_response_destroy(res); return ret; } +static bool _ctx_done_kmip_create(mongocrypt_kms_ctx_t *kms_ctx) { + BSON_ASSERT_PARAM(kms_ctx); + + kms_response_t *res = NULL; + + mongocrypt_status_t *status = kms_ctx->status; + bool ret = false; + char *uid; + + res = kms_response_parser_get_response(kms_ctx->parser); + if (!res) { + CLIENT_ERR("Error getting KMIP response: %s", kms_response_parser_error(kms_ctx->parser)); + goto done; + } + + uid = kms_kmip_response_get_unique_identifier(res); + if (!uid) { + CLIENT_ERR("Error getting UniqueIdentifer from KMIP Create response: %s", kms_response_get_error(res)); + goto done; + } + + if (!_mongocrypt_buffer_steal_from_string(&kms_ctx->result, uid)) { + CLIENT_ERR("Error storing KMS UniqueIdentifer result"); + bson_free(uid); + goto done; + } + ret = true; + +done: + kms_response_destroy(res); + return ret; +} + +static bool _ctx_done_kmip_encrypt(mongocrypt_kms_ctx_t *kms_ctx) { + BSON_ASSERT_PARAM(kms_ctx); + + kms_response_t *res = NULL; + + mongocrypt_status_t *status = kms_ctx->status; + bool ret = false; + uint8_t *ciphertext; + size_t ciphertext_len; + uint8_t *iv; + size_t iv_len; + _mongocrypt_buffer_t data_buf, iv_buf; + _mongocrypt_buffer_init(&data_buf); + _mongocrypt_buffer_init(&iv_buf); + + res = kms_response_parser_get_response(kms_ctx->parser); + if (!res) { + CLIENT_ERR("Error getting KMIP response: %s", kms_response_parser_error(kms_ctx->parser)); + goto done; + } + + ciphertext = kms_kmip_response_get_data(res, &ciphertext_len); + if (!ciphertext) { + CLIENT_ERR("Error getting data from KMIP Encrypt response: %s", kms_response_get_error(res)); + goto done; + } + + iv = kms_kmip_response_get_iv(res, &iv_len); + if (!iv) { + CLIENT_ERR("Error getting IV from KMIP Encrypt response: %s", kms_response_get_error(res)); + bson_free(ciphertext); + goto done; + } + + if (iv_len != MONGOCRYPT_IV_LEN) { + CLIENT_ERR("KMIP IV response has unexpected length: %zu", iv_len); + bson_free(ciphertext); + bson_free(iv); + goto done; + } + + if (!_mongocrypt_buffer_steal_from_data_and_size(&data_buf, ciphertext, ciphertext_len)) { + CLIENT_ERR("Error storing KMS Encrypt result"); + bson_free(ciphertext); + bson_free(iv); + goto done; + } + + if (!_mongocrypt_buffer_steal_from_data_and_size(&iv_buf, iv, iv_len)) { + CLIENT_ERR("Error storing KMS Encrypt IV"); + bson_free(ciphertext); + bson_free(iv); + goto done; + } + + const _mongocrypt_buffer_t results_buf[2] = {iv_buf, data_buf}; + if (!_mongocrypt_buffer_concat(&kms_ctx->result, results_buf, 2)) { + CLIENT_ERR("Error concatenating IV and ciphertext"); + goto done; + } + + ret = true; + +done: + kms_response_destroy(res); + _mongocrypt_buffer_cleanup(&iv_buf); + _mongocrypt_buffer_cleanup(&data_buf); + return ret; +} + +static bool _ctx_done_kmip_decrypt(mongocrypt_kms_ctx_t *kms_ctx) { + BSON_ASSERT_PARAM(kms_ctx); + + kms_response_t *res = NULL; + + mongocrypt_status_t *status = kms_ctx->status; + bool ret = false; + uint8_t *ciphertext; + size_t ciphertext_len; + + res = kms_response_parser_get_response(kms_ctx->parser); + if (!res) { + CLIENT_ERR("Error getting KMIP response: %s", kms_response_parser_error(kms_ctx->parser)); + goto done; + } + + ciphertext = kms_kmip_response_get_data(res, &ciphertext_len); + if (!ciphertext) { + CLIENT_ERR("Error getting data from KMIP Decrypt response: %s", kms_response_get_error(res)); + goto done; + } + + if (!_mongocrypt_buffer_steal_from_data_and_size(&kms_ctx->result, ciphertext, ciphertext_len)) { + CLIENT_ERR("Error storing KMS Decrypt result"); + bson_free(ciphertext); + goto done; + } + + ret = true; + +done: + kms_response_destroy(res); + return ret; +} + bool mongocrypt_kms_ctx_feed(mongocrypt_kms_ctx_t *kms, mongocrypt_binary_t *bytes) { if (!kms) { return false; } @@ -887,10 +1056,13 @@ case MONGOCRYPT_KMS_GCP_ENCRYPT: return _ctx_done_gcp(kms, "ciphertext"); case MONGOCRYPT_KMS_GCP_DECRYPT: return _ctx_done_gcp(kms, "plaintext"); case MONGOCRYPT_KMS_KMIP_REGISTER: return _ctx_done_kmip_register(kms); case MONGOCRYPT_KMS_KMIP_ACTIVATE: return _ctx_done_kmip_activate(kms); case MONGOCRYPT_KMS_KMIP_GET: return _ctx_done_kmip_get(kms); + case MONGOCRYPT_KMS_KMIP_ENCRYPT: return _ctx_done_kmip_encrypt(kms); + case MONGOCRYPT_KMS_KMIP_DECRYPT: return _ctx_done_kmip_decrypt(kms); + case MONGOCRYPT_KMS_KMIP_CREATE: return _ctx_done_kmip_create(kms); } } return true; } @@ -946,10 +1118,11 @@ } mongocrypt_status_destroy(kms->status); _mongocrypt_buffer_cleanup(&kms->msg); _mongocrypt_buffer_cleanup(&kms->result); bson_free(kms->endpoint); + bson_free(kms->kmsid); } bool mongocrypt_kms_ctx_message(mongocrypt_kms_ctx_t *kms, mongocrypt_binary_t *msg) { if (!kms) { return false; @@ -977,29 +1150,32 @@ *endpoint = kms->endpoint; return true; } bool _mongocrypt_kms_ctx_init_azure_auth(mongocrypt_kms_ctx_t *kms, - _mongocrypt_log_t *log, - _mongocrypt_opts_kms_providers_t *kms_providers, - _mongocrypt_endpoint_t *key_vault_endpoint) { + const mc_kms_creds_t *kc, + _mongocrypt_endpoint_t *key_vault_endpoint, + const char *kmsid, + _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms); - BSON_ASSERT_PARAM(kms_providers); + BSON_ASSERT_PARAM(kc); kms_request_opt_t *opt = NULL; mongocrypt_status_t *status; - _mongocrypt_endpoint_t *identity_platform_endpoint; + const _mongocrypt_endpoint_t *identity_platform_endpoint; char *scope = NULL; const char *hostname; char *request_string; bool ret = false; - _init_common(kms, log, MONGOCRYPT_KMS_AZURE_OAUTH); + _init_common(kms, log, MONGOCRYPT_KMS_AZURE_OAUTH, kmsid); status = kms->status; - identity_platform_endpoint = kms_providers->azure.identity_platform_endpoint; + BSON_ASSERT(kc->type == MONGOCRYPT_KMS_PROVIDER_AZURE); + identity_platform_endpoint = kc->value.azure.identity_platform_endpoint; + if (identity_platform_endpoint) { kms->endpoint = bson_strdup(identity_platform_endpoint->host_and_port); hostname = identity_platform_endpoint->host; } else { kms->endpoint = bson_strdup("login.microsoftonline.com"); @@ -1020,13 +1196,13 @@ BSON_ASSERT(opt); kms_request_opt_set_connection_close(opt, true); kms_request_opt_set_provider(opt, KMS_REQUEST_PROVIDER_AZURE); kms->req = kms_azure_request_oauth_new(hostname, scope, - kms_providers->azure.tenant_id, - kms_providers->azure.client_id, - kms_providers->azure.client_secret, + kc->value.azure.tenant_id, + kc->value.azure.client_id, + kc->value.azure.client_secret, opt); if (kms_request_get_error(kms->req)) { CLIENT_ERR("error constructing KMS message: %s", kms_request_get_error(kms->req)); goto fail; } @@ -1047,15 +1223,16 @@ kms_request_opt_destroy(opt); return ret; } bool _mongocrypt_kms_ctx_init_azure_wrapkey(mongocrypt_kms_ctx_t *kms, - _mongocrypt_log_t *log, _mongocrypt_opts_kms_providers_t *kms_providers, struct __mongocrypt_ctx_opts_t *ctx_opts, const char *access_token, - _mongocrypt_buffer_t *plaintext_key_material) { + _mongocrypt_buffer_t *plaintext_key_material, + const char *kmsid, + _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms); BSON_ASSERT_PARAM(ctx_opts); BSON_ASSERT_PARAM(plaintext_key_material); kms_request_opt_t *opt = NULL; @@ -1064,11 +1241,11 @@ char *payload = NULL; const char *host; char *request_string; bool ret = false; - _init_common(kms, log, MONGOCRYPT_KMS_AZURE_WRAPKEY); + _init_common(kms, log, MONGOCRYPT_KMS_AZURE_WRAPKEY, kmsid); status = kms->status; BSON_ASSERT(ctx_opts->kek.provider.azure.key_vault_endpoint); kms->endpoint = bson_strdup(ctx_opts->kek.provider.azure.key_vault_endpoint->host_and_port); @@ -1112,10 +1289,11 @@ bool _mongocrypt_kms_ctx_init_azure_unwrapkey(mongocrypt_kms_ctx_t *kms, _mongocrypt_opts_kms_providers_t *kms_providers, const char *access_token, _mongocrypt_key_doc_t *key, + const char *kmsid, _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms); BSON_ASSERT_PARAM(key); kms_request_opt_t *opt = NULL; @@ -1124,11 +1302,11 @@ char *payload = NULL; const char *host; char *request_string; bool ret = false; - _init_common(kms, log, MONGOCRYPT_KMS_AZURE_UNWRAPKEY); + _init_common(kms, log, MONGOCRYPT_KMS_AZURE_UNWRAPKEY, kmsid); status = kms->status; BSON_ASSERT(key->kek.provider.azure.key_vault_endpoint); kms->endpoint = bson_strdup(key->kek.provider.azure.key_vault_endpoint->host_and_port); @@ -1210,34 +1388,37 @@ ctx_with_status->status); return ret; } bool _mongocrypt_kms_ctx_init_gcp_auth(mongocrypt_kms_ctx_t *kms, - _mongocrypt_log_t *log, _mongocrypt_opts_t *crypt_opts, - _mongocrypt_opts_kms_providers_t *kms_providers, - _mongocrypt_endpoint_t *kms_endpoint) { + const mc_kms_creds_t *kc, + _mongocrypt_endpoint_t *kms_endpoint, + const char *kmsid, + _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms); - BSON_ASSERT_PARAM(kms_providers); + BSON_ASSERT_PARAM(kc); BSON_ASSERT_PARAM(crypt_opts); kms_request_opt_t *opt = NULL; mongocrypt_status_t *status; - _mongocrypt_endpoint_t *auth_endpoint; + const _mongocrypt_endpoint_t *auth_endpoint; char *scope = NULL; char *audience = NULL; const char *hostname; char *request_string; bool ret = false; ctx_with_status_t ctx_with_status; - _init_common(kms, log, MONGOCRYPT_KMS_GCP_OAUTH); + _init_common(kms, log, MONGOCRYPT_KMS_GCP_OAUTH, kmsid); status = kms->status; ctx_with_status.ctx = crypt_opts; ctx_with_status.status = mongocrypt_status_new(); - auth_endpoint = kms_providers->gcp.endpoint; + BSON_ASSERT(kc->type == MONGOCRYPT_KMS_PROVIDER_GCP); + + auth_endpoint = kc->value.gcp.endpoint; if (auth_endpoint) { kms->endpoint = bson_strdup(auth_endpoint->host_and_port); hostname = auth_endpoint->host; audience = bson_strdup_printf("https://%s/token", auth_endpoint->host); } else { @@ -1260,15 +1441,15 @@ kms_request_opt_set_provider(opt, KMS_REQUEST_PROVIDER_GCP); if (crypt_opts->sign_rsaes_pkcs1_v1_5) { kms_request_opt_set_crypto_hook_sign_rsaes_pkcs1_v1_5(opt, _sign_rsaes_pkcs1_v1_5_trampoline, &ctx_with_status); } kms->req = kms_gcp_request_oauth_new(hostname, - kms_providers->gcp.email, + kc->value.gcp.email, audience, scope, - (const char *)kms_providers->gcp.private_key.data, - kms_providers->gcp.private_key.len, + (const char *)kc->value.gcp.private_key.data, + kc->value.gcp.private_key.len, opt); if (kms_request_get_error(kms->req)) { CLIENT_ERR("error constructing KMS message: %s", kms_request_get_error(kms->req)); _mongocrypt_status_append(status, ctx_with_status.status); goto fail; @@ -1293,15 +1474,16 @@ mongocrypt_status_destroy(ctx_with_status.status); return ret; } bool _mongocrypt_kms_ctx_init_gcp_encrypt(mongocrypt_kms_ctx_t *kms, - _mongocrypt_log_t *log, _mongocrypt_opts_kms_providers_t *kms_providers, struct __mongocrypt_ctx_opts_t *ctx_opts, const char *access_token, - _mongocrypt_buffer_t *plaintext_key_material) { + _mongocrypt_buffer_t *plaintext_key_material, + const char *kmsid, + _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms); BSON_ASSERT_PARAM(ctx_opts); BSON_ASSERT_PARAM(kms_providers); BSON_ASSERT_PARAM(access_token); BSON_ASSERT_PARAM(plaintext_key_material); @@ -1312,11 +1494,11 @@ char *payload = NULL; const char *hostname; char *request_string; bool ret = false; - _init_common(kms, log, MONGOCRYPT_KMS_GCP_ENCRYPT); + _init_common(kms, log, MONGOCRYPT_KMS_GCP_ENCRYPT, kmsid); status = kms->status; if (ctx_opts->kek.provider.gcp.endpoint) { kms->endpoint = bson_strdup(ctx_opts->kek.provider.gcp.endpoint->host_and_port); hostname = ctx_opts->kek.provider.gcp.endpoint->host; @@ -1366,10 +1548,11 @@ bool _mongocrypt_kms_ctx_init_gcp_decrypt(mongocrypt_kms_ctx_t *kms, _mongocrypt_opts_kms_providers_t *kms_providers, const char *access_token, _mongocrypt_key_doc_t *key, + const char *kmsid, _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms); BSON_ASSERT_PARAM(kms_providers); BSON_ASSERT_PARAM(access_token); BSON_ASSERT_PARAM(key); @@ -1380,11 +1563,11 @@ char *payload = NULL; const char *hostname; char *request_string; bool ret = false; - _init_common(kms, log, MONGOCRYPT_KMS_GCP_DECRYPT); + _init_common(kms, log, MONGOCRYPT_KMS_GCP_DECRYPT, kmsid); status = kms->status; if (key->kek.provider.gcp.endpoint) { kms->endpoint = bson_strdup(key->kek.provider.gcp.endpoint->host_and_port); hostname = key->kek.provider.gcp.endpoint->host; @@ -1433,21 +1616,22 @@ bool _mongocrypt_kms_ctx_init_kmip_register(mongocrypt_kms_ctx_t *kms_ctx, const _mongocrypt_endpoint_t *endpoint, const uint8_t *secretdata, uint32_t secretdata_len, + const char *kmsid, _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms_ctx); BSON_ASSERT_PARAM(endpoint); BSON_ASSERT_PARAM(secretdata); mongocrypt_status_t *status; bool ret = false; const uint8_t *reqdata; size_t reqlen; - _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_REGISTER); + _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_REGISTER, kmsid); status = kms_ctx->status; kms_ctx->endpoint = bson_strdup(endpoint->host_and_port); _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT); kms_ctx->req = kms_kmip_request_register_secretdata_new(NULL /* reserved */, secretdata, secretdata_len); @@ -1469,21 +1653,22 @@ } bool _mongocrypt_kms_ctx_init_kmip_activate(mongocrypt_kms_ctx_t *kms_ctx, const _mongocrypt_endpoint_t *endpoint, const char *unique_identifier, + const char *kmsid, _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms_ctx); BSON_ASSERT_PARAM(endpoint); BSON_ASSERT_PARAM(unique_identifier); mongocrypt_status_t *status; bool ret = false; size_t reqlen; const uint8_t *reqdata; - _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_ACTIVATE); + _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_ACTIVATE, kmsid); status = kms_ctx->status; kms_ctx->endpoint = bson_strdup(endpoint->host_and_port); _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT); kms_ctx->req = kms_kmip_request_activate_new(NULL /* reserved */, unique_identifier); @@ -1505,21 +1690,22 @@ } bool _mongocrypt_kms_ctx_init_kmip_get(mongocrypt_kms_ctx_t *kms_ctx, const _mongocrypt_endpoint_t *endpoint, const char *unique_identifier, + const char *kmsid, _mongocrypt_log_t *log) { BSON_ASSERT_PARAM(kms_ctx); BSON_ASSERT_PARAM(endpoint); BSON_ASSERT_PARAM(unique_identifier); mongocrypt_status_t *status; bool ret = false; size_t reqlen; const uint8_t *reqdata; - _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_GET); + _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_GET, kmsid); status = kms_ctx->status; kms_ctx->endpoint = bson_strdup(endpoint->host_and_port); _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT); kms_ctx->req = kms_kmip_request_get_new(NULL /* reserved */, unique_identifier); @@ -1538,10 +1724,133 @@ ret = true; done: return ret; } +bool _mongocrypt_kms_ctx_init_kmip_create(mongocrypt_kms_ctx_t *kms_ctx, + const _mongocrypt_endpoint_t *endpoint, + const char *kmsid, + _mongocrypt_log_t *log) { + BSON_ASSERT_PARAM(kms_ctx); + BSON_ASSERT_PARAM(endpoint); + bool ret = false; + + _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_CREATE, kmsid); + mongocrypt_status_t *status = kms_ctx->status; + kms_ctx->endpoint = bson_strdup(endpoint->host_and_port); + _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT); + + kms_ctx->req = kms_kmip_request_create_new(NULL /* reserved */); + + if (kms_request_get_error(kms_ctx->req)) { + CLIENT_ERR("Error creating KMIP create request: %s", kms_request_get_error(kms_ctx->req)); + goto done; + } + + size_t reqlen; + const uint8_t *reqdata = kms_request_to_bytes(kms_ctx->req, &reqlen); + if (!_mongocrypt_buffer_copy_from_data_and_size(&kms_ctx->msg, reqdata, reqlen)) { + CLIENT_ERR("Error storing KMS request payload"); + goto done; + } + + ret = true; +done: + return ret; +} + +bool _mongocrypt_kms_ctx_init_kmip_encrypt(mongocrypt_kms_ctx_t *kms_ctx, + const _mongocrypt_endpoint_t *endpoint, + const char *unique_identifier, + const char *kmsid, + _mongocrypt_buffer_t *plaintext, + _mongocrypt_log_t *log) { + BSON_ASSERT_PARAM(kms_ctx); + BSON_ASSERT_PARAM(endpoint); + BSON_ASSERT_PARAM(plaintext); + bool ret = false; + + _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_ENCRYPT, kmsid); + mongocrypt_status_t *status = kms_ctx->status; + kms_ctx->endpoint = bson_strdup(endpoint->host_and_port); + _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT); + + kms_ctx->req = + kms_kmip_request_encrypt_new(NULL /* reserved */, unique_identifier, plaintext->data, plaintext->len); + + if (kms_request_get_error(kms_ctx->req)) { + CLIENT_ERR("Error creating KMIP encrypt request: %s", kms_request_get_error(kms_ctx->req)); + goto done; + } + + size_t reqlen; + const uint8_t *reqdata = kms_request_to_bytes(kms_ctx->req, &reqlen); + if (!_mongocrypt_buffer_copy_from_data_and_size(&kms_ctx->msg, reqdata, reqlen)) { + CLIENT_ERR("Error storing KMS request payload"); + goto done; + } + + ret = true; +done: + return ret; +} + +bool _mongocrypt_kms_ctx_init_kmip_decrypt(mongocrypt_kms_ctx_t *kms_ctx, + const _mongocrypt_endpoint_t *endpoint, + const char *kmsid, + _mongocrypt_key_doc_t *key, + _mongocrypt_log_t *log) { + BSON_ASSERT_PARAM(kms_ctx); + BSON_ASSERT_PARAM(endpoint); + BSON_ASSERT_PARAM(key); + bool ret = false; + + _init_common(kms_ctx, log, MONGOCRYPT_KMS_KMIP_DECRYPT, kmsid); + mongocrypt_status_t *status = kms_ctx->status; + kms_ctx->endpoint = bson_strdup(endpoint->host_and_port); + _mongocrypt_apply_default_port(&kms_ctx->endpoint, DEFAULT_KMIP_PORT); + + _mongocrypt_buffer_t iv; + if (!_mongocrypt_buffer_from_subrange(&iv, &key->key_material, 0, MONGOCRYPT_IV_LEN)) { + CLIENT_ERR("Error getting IV from key material"); + goto done; + } + _mongocrypt_buffer_t ciphertext; + if (!_mongocrypt_buffer_from_subrange(&ciphertext, + &key->key_material, + MONGOCRYPT_IV_LEN, + key->key_material.len - MONGOCRYPT_IV_LEN)) { + CLIENT_ERR("Error getting ciphertext from key material"); + goto done; + } + + BSON_ASSERT(key->kek.kms_provider == MONGOCRYPT_KMS_PROVIDER_KMIP); + BSON_ASSERT(key->kek.provider.kmip.delegated); + kms_ctx->req = kms_kmip_request_decrypt_new(NULL /* reserved */, + key->kek.provider.kmip.key_id, + ciphertext.data, + ciphertext.len, + iv.data, + iv.len); + + if (kms_request_get_error(kms_ctx->req)) { + CLIENT_ERR("Error creating KMIP decrypt request: %s", kms_request_get_error(kms_ctx->req)); + goto done; + } + + size_t reqlen; + const uint8_t *reqdata = kms_request_to_bytes(kms_ctx->req, &reqlen); + if (!_mongocrypt_buffer_copy_from_data_and_size(&kms_ctx->msg, reqdata, reqlen)) { + CLIENT_ERR("Error storing KMS request payload"); + goto done; + } + + ret = true; +done: + return ret; +} + static const char *set_and_ret(const char *what, uint32_t *len) { BSON_ASSERT_PARAM(what); if (len) { BSON_ASSERT(size_to_uint32(strlen(what), len)); @@ -1551,20 +1860,7 @@ const char *mongocrypt_kms_ctx_get_kms_provider(mongocrypt_kms_ctx_t *kms, uint32_t *len) { BSON_ASSERT_PARAM(kms); /* len is checked in set_and_ret () before it is used */ - switch (kms->req_type) { - default: BSON_ASSERT(false && "unknown KMS request type"); - case MONGOCRYPT_KMS_AWS_ENCRYPT: - case MONGOCRYPT_KMS_AWS_DECRYPT: return set_and_ret("aws", len); - case MONGOCRYPT_KMS_AZURE_OAUTH: - case MONGOCRYPT_KMS_AZURE_WRAPKEY: - case MONGOCRYPT_KMS_AZURE_UNWRAPKEY: return set_and_ret("azure", len); - case MONGOCRYPT_KMS_GCP_OAUTH: - case MONGOCRYPT_KMS_GCP_ENCRYPT: - case MONGOCRYPT_KMS_GCP_DECRYPT: return set_and_ret("gcp", len); - case MONGOCRYPT_KMS_KMIP_REGISTER: - case MONGOCRYPT_KMS_KMIP_ACTIVATE: - case MONGOCRYPT_KMS_KMIP_GET: return set_and_ret("kmip", len); - } + return set_and_ret(kms->kmsid, len); }