summaryrefslogtreecommitdiff
path: root/src/mongo/db/matcher
diff options
context:
space:
mode:
authorTed Tuckman <ted.tuckman@mongodb.com>2019-01-31 09:03:34 -0500
committerTed Tuckman <ted.tuckman@mongodb.com>2019-02-15 14:53:03 -0500
commitda8140d860635544646e43e93a64ffb0fdd42a3e (patch)
treee780521729669cfec5828b20c02f4cfd0f41c27a /src/mongo/db/matcher
parent2fabe02b172a069cf3309683ea58ddab96c5c8a3 (diff)
downloadmongo-da8140d860635544646e43e93a64ffb0fdd42a3e.tar.gz
SERVER-39236 Add encrypt schema IDL types
Diffstat (limited to 'src/mongo/db/matcher')
-rw-r--r--src/mongo/db/matcher/SConscript15
-rw-r--r--src/mongo/db/matcher/schema/encrypt_schema.idl132
-rw-r--r--src/mongo/db/matcher/schema/encrypt_schema_types.cpp75
-rw-r--r--src/mongo/db/matcher/schema/encrypt_schema_types.h121
-rw-r--r--src/mongo/db/matcher/schema/encrypt_schema_types_test.cpp120
5 files changed, 461 insertions, 2 deletions
diff --git a/src/mongo/db/matcher/SConscript b/src/mongo/db/matcher/SConscript
index b342cd71214..06d5c7b0549 100644
--- a/src/mongo/db/matcher/SConscript
+++ b/src/mongo/db/matcher/SConscript
@@ -51,6 +51,7 @@ env.Library(
'matcher.cpp',
'matcher_type_set.cpp',
'rewrite_expr.cpp',
+ 'schema/encrypt_schema_types.cpp',
'schema/expression_internal_schema_all_elem_match_from_index.cpp',
'schema/expression_internal_schema_allowed_properties.cpp',
'schema/expression_internal_schema_cond.cpp',
@@ -66,6 +67,7 @@ env.Library(
'schema/expression_internal_schema_xor.cpp',
'schema/json_pointer.cpp',
'schema/json_schema_parser.cpp',
+ env.Idlc('schema/encrypt_schema.idl')[0],
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
@@ -77,12 +79,23 @@ env.Library(
'$BUILD_DIR/mongo/db/query/collation/collator_interface',
'$BUILD_DIR/mongo/db/query/query_knobs',
'$BUILD_DIR/mongo/db/pipeline/expression',
+ '$BUILD_DIR/mongo/idl/idl_parser',
'$BUILD_DIR/third_party/shim_pcrecpp',
'path',
],
)
env.CppUnitTest(
+ target='encrypt_schema_types_test',
+ source=[
+ 'schema/encrypt_schema_types_test.cpp'
+ ],
+ LIBDEPS=[
+ 'expressions',
+ ],
+)
+
+env.CppUnitTest(
target='json_pointer_test',
source=['schema/json_pointer_test.cpp'],
LIBDEPS=[
@@ -190,5 +203,3 @@ env.CppUnitTest(
'expressions',
],
)
-
-
diff --git a/src/mongo/db/matcher/schema/encrypt_schema.idl b/src/mongo/db/matcher/schema/encrypt_schema.idl
new file mode 100644
index 00000000000..83112526f55
--- /dev/null
+++ b/src/mongo/db/matcher/schema/encrypt_schema.idl
@@ -0,0 +1,132 @@
+# Copyright (C) 2019-present MongoDB, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Server Side Public License, version 1,
+# as published by MongoDB, Inc.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Server Side Public License for more details.
+#
+# You should have received a copy of the Server Side Public License
+# along with this program. If not, see
+# <http://www.mongodb.com/licensing/server-side-public-license>.
+#
+# As a special exception, the copyright holders give permission to link the
+# code of portions of this program with the OpenSSL library under certain
+# conditions as described in each individual source file and distribute
+# linked combinations including the program with the OpenSSL library. You
+# must comply with the Server Side Public License in all respects for
+# all of the code used other than as permitted herein. If you modify file(s)
+# with this exception, you may extend this exception to your version of the
+# file(s), but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version. If you delete this
+# exception statement from all source files in the program, then also delete
+# it in the license file.
+#
+
+global:
+ cpp_namespace: "mongo"
+ cpp_includes:
+ - "mongo/db/matcher/schema/encrypt_schema_types.h"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+
+types:
+ encryptSchemaAnyType:
+ bson_serialization_type: any
+ description: "Holds a to-be-encrypted BSONElement of any type."
+ cpp_type: "mongo::EncryptSchemaAnyType"
+ serializer: mongo::EncryptSchemaAnyType::serializeToBSON
+ deserializer: mongo::EncryptSchemaAnyType::parseFromBSON
+
+ encryptSchemaKeyId:
+ bson_serialization_type: any
+ description: "A string pointing to the key id or an array UUIDs identifying a set of keys."
+ cpp_type: "mongo::EncryptSchemaKeyId"
+ serializer: mongo::EncryptSchemaKeyId::serializeToBSON
+ deserializer: mongo::EncryptSchemaKeyId::parseFromBSON
+
+enums:
+ FleAlgorithm:
+ description: "The algorithm used to encrypt fields for field level encryption."
+ type: string
+ values:
+ kDeterministic: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
+ kRandom: "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
+
+structs:
+ # Maps to the encrypt keyword in JSON Schema.
+ EncryptionInfo:
+ description: "Represents the fields that users can specify within the encryptMetadata
+ subobject in a JSON Schema."
+ strict: true
+ fields:
+ bsonType:
+ description: "Specifies the type of the to-be-encrypted value."
+ type: string
+ optional: true
+ algorithm:
+ description: "The encryption algorithm to be used."
+ type: FleAlgorithm
+ optional: true
+ initializationVector:
+ description: "Provided to be used for unique encryption for different collections."
+ type: bindata_generic
+ optional: true
+ keyId:
+ description: "A JSONPointer to a key or an array of UUIDs identifying a set of keys."
+ type: encryptSchemaKeyId
+ optional: true
+
+ # Maps to "encryptMetadata" in JSON Schema.
+ EncryptionMetadata:
+ description: "The fields that can be applied to children in the schema
+ with the encrypt keyword."
+ strict: true
+ fields:
+ algorithm:
+ description: "The encryption algorithm to be used."
+ type: FleAlgorithm
+ optional: true
+ initializationVector:
+ description: "Provided to be used for unique encryption for different collections."
+ type: bindata_generic
+ optional: true
+ keyId:
+ description: "A JSONPointer to a key or an array of UUIDs identifying a set of keys."
+ type: encryptSchemaKeyId
+ optional: true
+
+ EncryptionPlaceholder:
+ description: "Implements Encryption BinData (subtype 6) sub-subtype 0, the intent-to-encrypt
+ mapping. Contains a value to encrypt and a description of how it should be encrypted."
+ strict: true
+ fields:
+ a:
+ description: "The encryption algorithm to be used."
+ type: FleAlgorithm
+ cpp_name: algorithm
+ iv:
+ description: "Provided to be used for unique encryption for different collections."
+ type: bindata_generic
+ cpp_name: initializationVector
+ # Only present if algorithm is deterministic.
+ optional: true
+ ki:
+ description: "Used to query the key vault by _id. If omitted, ka must be specified."
+ type: uuid
+ cpp_name: keyId
+ optional: true
+ ka:
+ description: "Used to query the key vault by keyAltName. If omitted,
+ ki must be specified."
+ type: encryptSchemaAnyType
+ cpp_name: keyAltName
+ optional: true
+ v:
+ description: "value to encrypt"
+ type: encryptSchemaAnyType
+ cpp_name: encryptSchemaAnyType
diff --git a/src/mongo/db/matcher/schema/encrypt_schema_types.cpp b/src/mongo/db/matcher/schema/encrypt_schema_types.cpp
new file mode 100644
index 00000000000..5ce2fbfabaa
--- /dev/null
+++ b/src/mongo/db/matcher/schema/encrypt_schema_types.cpp
@@ -0,0 +1,75 @@
+/**
+ * Copyright (C) 2019-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/matcher/schema/encrypt_schema_types.h"
+#include "mongo/idl/idl_parser.h"
+
+namespace mongo {
+
+EncryptSchemaKeyId EncryptSchemaKeyId::parseFromBSON(const BSONElement& element) {
+ if (element.type() == BSONType::String) {
+ return EncryptSchemaKeyId(element.String());
+ } else if (element.type() == BSONType::Array) {
+ std::vector<UUID> keys;
+
+ for (auto&& arrayElement : element.embeddedObject()) {
+ if (arrayElement.binDataType() == BinDataType::newUUID) {
+ const auto uuid = uassertStatusOK(UUID::parse(arrayElement));
+
+ keys.emplace_back(uuid);
+ } else {
+ uasserted(51084,
+ str::stream() << "Array elements must have type UUID, found "
+ << arrayElement.binDataType());
+ }
+ }
+ return EncryptSchemaKeyId(keys);
+ } else {
+ uasserted(51085,
+ str::stream()
+ << "Expected either string or array of UUID for EncryptSchemaKeyId, found "
+ << element.type());
+ }
+ MONGO_UNREACHABLE;
+}
+
+void EncryptSchemaKeyId::serializeToBSON(StringData fieldName, BSONObjBuilder* builder) const {
+ if (_type == Type::kUUIDs) {
+ BSONArrayBuilder arrBuilder(builder->subarrayStart(fieldName));
+ for (auto uuid : _uuids) {
+ uuid.appendToArrayBuilder(&arrBuilder);
+ }
+ arrBuilder.doneFast();
+ } else {
+ builder->append(fieldName, _strKeyId);
+ }
+}
+} // namespace mongo
diff --git a/src/mongo/db/matcher/schema/encrypt_schema_types.h b/src/mongo/db/matcher/schema/encrypt_schema_types.h
new file mode 100644
index 00000000000..504b605cca5
--- /dev/null
+++ b/src/mongo/db/matcher/schema/encrypt_schema_types.h
@@ -0,0 +1,121 @@
+/**
+ * Copyright (C) 2019-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "mongo/bson/bsonelement.h"
+#include "mongo/bson/bsonobj.h"
+#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/util/uuid.h"
+
+namespace mongo {
+
+/**
+ * A string pointing to the key id or an array of UUIDs identifying a set of keys.
+ */
+class EncryptSchemaKeyId {
+ friend class EncryptionInfoNormalized;
+ friend class EncryptionMetadata;
+ friend class EncryptionInfo;
+
+public:
+ enum class Type {
+ kUUIDs,
+ kJSONPointer,
+ };
+
+ static EncryptSchemaKeyId parseFromBSON(const BSONElement& element);
+
+ EncryptSchemaKeyId(const std::string key)
+ : _strKeyId(std::move(key)), _type(Type::kJSONPointer) {}
+
+ EncryptSchemaKeyId(std::vector<UUID> keys) : _uuids(std::move(keys)), _type(Type::kUUIDs) {}
+
+ void serializeToBSON(StringData fieldName, BSONObjBuilder* builder) const;
+
+ Type type() const {
+ return _type;
+ }
+
+ /**
+ * Callers must check that the result of type() is kUUIDs first.
+ */
+ const std::vector<UUID>& uuids() const {
+ invariant(_type == Type::kUUIDs);
+ return _uuids;
+ }
+
+ /**
+ * Callers must check that the result of type() is kJSONPointer first.
+ */
+ const std::string& jsonPointer() const {
+ invariant(_type == Type::kJSONPointer);
+ return _strKeyId;
+ }
+
+private:
+ // The default constructor is required to exist by IDL, but is private because it does not
+ // construct a valid EncryptSchemaKeyId and should not be called.
+ EncryptSchemaKeyId() = default;
+
+ std::string _strKeyId;
+ std::vector<UUID> _uuids;
+
+ Type _type;
+};
+
+/**
+ * Class to represent an element with any type from IDL. The caller must ensure that the backing
+ * BSON stays alive while this type is in use.
+ */
+class EncryptSchemaAnyType {
+public:
+ /**
+ * This type is currenty only used for serialization, not parsing.
+ */
+ static EncryptSchemaAnyType parseFromBSON(const BSONElement& element) {
+ MONGO_UNREACHABLE;
+ }
+
+ void serializeToBSON(StringData fieldName, BSONObjBuilder* builder) const {
+ builder->appendAs(_element, fieldName);
+ }
+
+ void setElement(const BSONElement& element) {
+ _element = element;
+ }
+
+private:
+ BSONElement _element;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/matcher/schema/encrypt_schema_types_test.cpp b/src/mongo/db/matcher/schema/encrypt_schema_types_test.cpp
new file mode 100644
index 00000000000..229b66ccb0f
--- /dev/null
+++ b/src/mongo/db/matcher/schema/encrypt_schema_types_test.cpp
@@ -0,0 +1,120 @@
+/**
+ * Copyright (C) 2019-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/bson/bsonelement.h"
+#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/db/matcher/schema/encrypt_schema_gen.h"
+#include "mongo/db/matcher/schema/encrypt_schema_types.h"
+#include "mongo/unittest/bson_test_util.h"
+#include "mongo/unittest/death_test.h"
+#include "mongo/unittest/unittest.h"
+#include "mongo/util/uuid.h"
+
+namespace mongo {
+namespace {
+
+TEST(EncryptSchemaTest, KeyIDTypePointerTest) {
+ auto tempObj = BSON("pointer"
+ << "/pointer/pointing");
+ auto elem = tempObj["pointer"];
+ auto keyid = EncryptSchemaKeyId::parseFromBSON(elem);
+ ASSERT(keyid.type() == EncryptSchemaKeyId::Type::kJSONPointer);
+ ASSERT_FALSE(UUID::parse(keyid.jsonPointer()).isOK());
+}
+
+TEST(EncryptSchemaTest, KeyIDTypeArrayTest) {
+ auto tempObj =
+ BSON("array" << BSON_ARRAY(UUID::gen() << UUID::gen() << UUID::gen() << UUID::gen()));
+ auto elem = tempObj["array"];
+ auto keyid = EncryptSchemaKeyId::parseFromBSON(elem);
+ ASSERT(keyid.type() == EncryptSchemaKeyId::Type::kUUIDs);
+}
+
+TEST(EncryptSchemaTest, KeyIDTypeInvalidTest) {
+ auto tempObj = BSON("invalid" << 5);
+ auto elem = tempObj["invalid"];
+ ASSERT_THROWS(EncryptSchemaKeyId::parseFromBSON(elem), DBException);
+}
+
+DEATH_TEST(EncryptSchemaTest, KeyIDPointerToBSON, "invariant") {
+ BSONObjBuilder builder;
+ EncryptSchemaKeyId pointerKeyID{"/pointer"};
+ pointerKeyID.serializeToBSON("pointer", &builder);
+ auto resultObj = builder.obj();
+ BSONElement pointer = resultObj["pointer"];
+ ASSERT(pointer);
+ ASSERT_EQ(pointer.type(), BSONType::String);
+ EncryptSchemaKeyId pointerParsed = EncryptSchemaKeyId::parseFromBSON(pointer);
+ pointerParsed.uuids();
+}
+
+DEATH_TEST(EncryptSchemaTest, KeyIDArrayToBSON, "invariant") {
+ BSONObjBuilder builder;
+ std::vector<UUID> vect{UUID::gen(), UUID::gen()};
+ EncryptSchemaKeyId vectKeyId{vect};
+ vectKeyId.serializeToBSON("array", &builder);
+ auto resultObj = builder.obj();
+ BSONElement array = resultObj["array"];
+ ASSERT(array);
+ ASSERT_EQ(array.type(), BSONType::Array);
+ ASSERT_EQ(array.Array().size(), unsigned{2});
+ EncryptSchemaKeyId parsed = EncryptSchemaKeyId::parseFromBSON(array);
+ parsed.jsonPointer();
+}
+
+TEST(EncryptSchemaTest, ParseFullEncryptObjectFromBSON) {
+ BSONObj encryptInfoBSON = BSON("bsonType"
+ << "int"
+ << "algorithm"
+ << "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
+ << "keyId"
+ << "/pointer");
+ IDLParserErrorContext ctxt("encrypt");
+ auto encryptInfo = EncryptionInfo::parse(ctxt, encryptInfoBSON);
+ ASSERT_EQ(encryptInfo.getBsonType().get(), "int");
+ ASSERT_TRUE(encryptInfo.getAlgorithm().get() == FleAlgorithmEnum::kDeterministic);
+ EncryptSchemaKeyId keyid = encryptInfo.getKeyId().get();
+ ASSERT_TRUE(keyid.type() == EncryptSchemaKeyId::Type::kJSONPointer);
+ ASSERT_EQ(keyid.jsonPointer(), "/pointer");
+}
+
+TEST(EncryptSchemaTest, WrongTypeFailsParse) {
+ BSONObj encryptInfoBSON = BSON("keyId" << 2);
+ IDLParserErrorContext ctxt("encrypt");
+ ASSERT_THROWS_CODE(EncryptionInfo::parse(ctxt, encryptInfoBSON), DBException, 51085);
+ encryptInfoBSON = BSON("algorithm"
+ << "garbage");
+ ASSERT_THROWS_CODE(
+ EncryptionInfo::parse(ctxt, encryptInfoBSON), DBException, ErrorCodes::BadValue);
+}
+
+} // namespace
+} // namespace mongo