/* * 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. */ #include "mongocrypt-ciphertext-private.h" #include "mongocrypt-private.h" void _mongocrypt_ciphertext_init(_mongocrypt_ciphertext_t *ciphertext) { BSON_ASSERT_PARAM(ciphertext); memset(ciphertext, 0, sizeof(*ciphertext)); } void _mongocrypt_ciphertext_cleanup(_mongocrypt_ciphertext_t *ciphertext) { if (!ciphertext) { return; } _mongocrypt_buffer_cleanup(&ciphertext->key_id); _mongocrypt_buffer_cleanup(&ciphertext->data); } bool _mongocrypt_ciphertext_parse_unowned(_mongocrypt_buffer_t *in, _mongocrypt_ciphertext_t *ciphertext, mongocrypt_status_t *status) { uint32_t offset; /* From BSON Binary subtype 6 specification: struct fle_blob { uint8 fle_blob_subtype = (1 or 2); uint8 key_uuid[16]; uint8 original_bson_type; uint8 ciphertext[ciphertext_length]; } */ if (!ciphertext) { CLIENT_ERR("ciphertext cannot be null"); return false; } if (!in) { CLIENT_ERR("in parameter cannot be null"); return false; } if (!status) { CLIENT_ERR("status cannot be null"); return false; } offset = 0; /* At a minimum, a ciphertext must be 19 bytes: * fle_blob_subtype (1) + * key_uuid (16) + * original_bson_type (1) + * ciphertext (> 0) */ if (in->len < 19) { CLIENT_ERR("malformed ciphertext, too small"); return false; } ciphertext->blob_subtype = in->data[0]; offset += 1; /* TODO: merge new changes. */ if (ciphertext->blob_subtype != 1 && ciphertext->blob_subtype != 2) { CLIENT_ERR("malformed ciphertext, expected blob subtype of 1 or 2"); return false; } _mongocrypt_buffer_init(&ciphertext->key_id); ciphertext->key_id.data = in->data + offset; ciphertext->key_id.len = 16; ciphertext->key_id.subtype = BSON_SUBTYPE_UUID; offset += 16; ciphertext->original_bson_type = in->data[offset]; offset += 1; _mongocrypt_buffer_init(&ciphertext->data); ciphertext->data.data = in->data + offset; ciphertext->data.len = in->len - offset; return true; } bool _mongocrypt_serialize_ciphertext(_mongocrypt_ciphertext_t *ciphertext, _mongocrypt_buffer_t *out) { uint32_t offset; /* From BSON Binary subtype 6 specification: struct fle_blob { uint8 fle_blob_subtype = (1 or 2); uint8 key_uuid[16]; uint8 original_bson_type; uint8 ciphertext[ciphertext_length]; } */ if (!ciphertext || !out) { return false; } if (ciphertext->key_id.len != 16) { return false; } if (ciphertext->key_id.len > (UINT32_MAX - ciphertext->data.len - 1) || ciphertext->key_id.len > (SIZE_MAX - ciphertext->data.len - 1)) { return false; } _mongocrypt_buffer_init(out); offset = 0; out->len = 1 + ciphertext->key_id.len + 1 + ciphertext->data.len; out->data = bson_malloc0(out->len); BSON_ASSERT(out->data); out->owned = true; /* ciphertext->blob_subtype is an enum and easily fits in uint8_t */ out->data[offset] = (uint8_t)ciphertext->blob_subtype; offset += 1; memcpy(out->data + offset, ciphertext->key_id.data, ciphertext->key_id.len); offset += ciphertext->key_id.len; out->data[offset] = ciphertext->original_bson_type; offset += 1; memcpy(out->data + offset, ciphertext->data.data, ciphertext->data.len); return true; } /* From "FLE and AEAD" doc: A = Associated Data = fle_blob_subtype + key_uuid[16] + original_bson_type */ bool _mongocrypt_ciphertext_serialize_associated_data(_mongocrypt_ciphertext_t *ciphertext, _mongocrypt_buffer_t *out) { BSON_ASSERT_PARAM(ciphertext); uint32_t bytes_written = 0; if (!out) { return false; } _mongocrypt_buffer_init(out); if (!ciphertext->original_bson_type) { return false; } if (!_mongocrypt_buffer_is_uuid(&ciphertext->key_id)) { return false; } if ((ciphertext->blob_subtype != MC_SUBTYPE_FLE1DeterministicEncryptedValue) && (ciphertext->blob_subtype != MC_SUBTYPE_FLE1RandomEncryptedValue)) { return false; } if (ciphertext->key_id.len > (UINT32_MAX - 2)) { return false; } out->len = 1 + ciphertext->key_id.len + 1; out->data = bson_malloc(out->len); BSON_ASSERT(out->data); out->owned = true; out->data[bytes_written++] = (uint8_t)ciphertext->blob_subtype; memcpy(out->data + bytes_written, ciphertext->key_id.data, ciphertext->key_id.len); bytes_written += ciphertext->key_id.len; out->data[bytes_written++] = (uint8_t)ciphertext->original_bson_type; return true; }