summaryrefslogtreecommitdiff
path: root/src/mongo/crypto/fle_crypto.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/crypto/fle_crypto.cpp')
-rw-r--r--src/mongo/crypto/fle_crypto.cpp118
1 files changed, 91 insertions, 27 deletions
diff --git a/src/mongo/crypto/fle_crypto.cpp b/src/mongo/crypto/fle_crypto.cpp
index 4cfa6749f1d..8a189c9a1c5 100644
--- a/src/mongo/crypto/fle_crypto.cpp
+++ b/src/mongo/crypto/fle_crypto.cpp
@@ -926,6 +926,15 @@ void convertToFLE2Payload(FLEKeyVault* keyVault,
} else {
uasserted(6410100, "No other FLE2 placeholders supported at this time.");
}
+ } else if (ep.getAlgorithm() == Fle2AlgorithmInt::kUnindexed) {
+ uassert(6379102,
+ str::stream() << "Type '" << typeName(el.type())
+ << "' is not a valid type for FLE 2 encryption",
+ isFLE2UnindexedSupportedType(el.type()));
+
+ auto payload = FLE2UnindexedEncryptedValue::serialize(userKey, el);
+ builder->appendBinData(
+ fieldNameToSerialize, payload.size(), BinDataType::Encrypt, payload.data());
} else {
uasserted(6338603, "Only FLE 2 style encryption placeholders are supported");
}
@@ -957,8 +966,6 @@ void collectEDCServerInfo(std::vector<EDCServerPayloadInfo>* pFields,
ConstDataRange cdr,
StringData fieldPath) {
- // TODO - validate acceptable types - kFLE2InsertUpdatePayload or kFLE2UnindexedEncryptedValue
- // or kFLE2EqualityIndexedValue
// TODO - validate field is actually indexed in the schema?
auto [encryptedTypeBinding, subCdr] = fromEncryptedConstDataRange(cdr);
@@ -970,6 +977,9 @@ void collectEDCServerInfo(std::vector<EDCServerPayloadInfo>* pFields,
} else if (encryptedType == EncryptedBinDataType::kFLE2FindEqualityPayload) {
// No-op
return;
+ } else if (encryptedType == EncryptedBinDataType::kFLE2UnindexedEncryptedValue) {
+ // No-op
+ return;
}
uasserted(6373503,
str::stream() << "Unexpected encrypted payload type: "
@@ -998,36 +1008,40 @@ void convertServerPayload(ConstDataRange cdr,
if (encryptedTypeBinding == EncryptedBinDataType::kFLE2FindEqualityPayload) {
builder->appendBinData(fieldPath, cdr.length(), BinDataType::Encrypt, cdr.data<char>());
return;
- }
+ } else if (encryptedTypeBinding == EncryptedBinDataType::kFLE2InsertUpdatePayload) {
- if (it.it == it.end) {
- return;
- }
+ if (it.it == it.end) {
+ return;
+ }
- // TODO : renable this when find is working on query (find server number)
- // uassert(6373505, "Unexpected end of iterator", it.it != it.end);
- auto payload = *(it.it);
+ uassert(6373505, "Unexpected end of iterator", it.it != it.end);
+ auto payload = *(it.it);
- // TODO - validate acceptable types - kFLE2InsertUpdatePayload or kFLE2UnindexedEncryptedValue
- // or kFLE2EqualityIndexedValue
- // TODO - validate field is actually indexed in the schema?
+ // TODO - validate field is actually indexed in the schema?
- FLE2IndexedEqualityEncryptedValue sp(payload.payload, payload.count);
+ FLE2IndexedEqualityEncryptedValue sp(payload.payload, payload.count);
- uassert(6373506,
- str::stream() << "Type '" << typeName(sp.bsonType)
- << "' is not a valid type for FLE 2 encryption",
- isFLE2EqualityIndexedSupportedType(sp.bsonType));
+ uassert(6373506,
+ str::stream() << "Type '" << typeName(sp.bsonType)
+ << "' is not a valid type for FLE 2 encryption",
+ isFLE2EqualityIndexedSupportedType(sp.bsonType));
- auto swEncrypted = sp.serialize(FLETokenFromCDR<FLETokenType::ServerDataEncryptionLevel1Token>(
- payload.payload.getServerEncryptionToken()));
- uassertStatusOK(swEncrypted);
- toEncryptedBinData(fieldPath,
- EncryptedBinDataType::kFLE2EqualityIndexedValue,
- ConstDataRange(swEncrypted.getValue()),
- builder);
+ auto swEncrypted =
+ sp.serialize(FLETokenFromCDR<FLETokenType::ServerDataEncryptionLevel1Token>(
+ payload.payload.getServerEncryptionToken()));
+ uassertStatusOK(swEncrypted);
+ toEncryptedBinData(fieldPath,
+ EncryptedBinDataType::kFLE2EqualityIndexedValue,
+ ConstDataRange(swEncrypted.getValue()),
+ builder);
- pTags->push_back({EDCServerCollection::generateTag(payload)});
+ pTags->push_back({EDCServerCollection::generateTag(payload)});
+ } else if (encryptedTypeBinding == EncryptedBinDataType::kFLE2UnindexedEncryptedValue) {
+ builder->appendBinData(fieldPath, cdr.length(), BinDataType::Encrypt, cdr.data());
+ return;
+ } else {
+ uassert(6379103, "Unexpected type binding", false);
+ }
it.it++;
}
@@ -1317,6 +1331,8 @@ std::pair<BSONType, std::vector<uint8_t>> FLEClientCrypto::decrypt(ConstDataRang
return {ieev.bsonType, userData};
+ } else if (pair.first == EncryptedBinDataType::kFLE2UnindexedEncryptedValue) {
+ return FLE2UnindexedEncryptedValue::deserialize(keyVault, cdr);
} else if (pair.first == EncryptedBinDataType::kRandom ||
pair.first == EncryptedBinDataType::kDeterministic) {
return {EOO, std::vector<uint8_t>()};
@@ -1404,9 +1420,11 @@ void FLEClientCrypto::validateDocument(const BSONObj& doc,
auto tag = EDCServerCollection::generateTag(ieev);
tags.insert({tag, field.first});
+ } else {
+ uassert(6379105,
+ str::stream() << "Field '" << field.first << "' must be marked unindexed",
+ encryptedTypeBinding == EncryptedBinDataType::kFLE2UnindexedEncryptedValue);
}
-
- // TODO - support unindexed
}
BSONElement safeContent = doc[kSafeContent];
@@ -1946,6 +1964,52 @@ StatusWith<std::vector<uint8_t>> FLE2IndexedEqualityEncryptedValue::serialize(
return serializedServerValue;
}
+std::vector<uint8_t> FLE2UnindexedEncryptedValue::serialize(const FLEUserKeyAndId& userKey,
+ const BSONElement& element) {
+ BSONType bsonType = element.type();
+ uassert(6379107, "Invalid BSON data type", isFLE2UnindexedSupportedType(bsonType));
+
+ auto value = ConstDataRange(element.value(), element.value() + element.valuesize());
+ auto cdrKeyId = userKey.keyId.toCDR();
+ auto cdrKey = userKey.key.toCDR();
+
+ auto cipherTextSize = crypto::fle2AeadCipherOutputLength(value.length());
+ std::vector<uint8_t> buf(assocDataSize + cipherTextSize);
+ DataRangeCursor adc(buf);
+ adc.writeAndAdvance(static_cast<uint8_t>(EncryptedBinDataType::kFLE2UnindexedEncryptedValue));
+ adc.writeAndAdvance(cdrKeyId);
+ adc.writeAndAdvance(static_cast<uint8_t>(bsonType));
+
+ ConstDataRange assocData(buf.data(), assocDataSize);
+ auto cipherText = uassertStatusOK(encryptDataWithAssociatedData(cdrKey, assocData, value));
+ uassert(6379106, "Cipher text size mismatch", cipherTextSize == cipherText.size());
+ adc.writeAndAdvance(ConstDataRange(cipherText));
+
+ return buf;
+}
+
+std::pair<BSONType, std::vector<uint8_t>> FLE2UnindexedEncryptedValue::deserialize(
+ FLEKeyVault* keyVault, ConstDataRange blob) {
+
+ auto [assocDataCdr, cipherTextCdr] = blob.split(assocDataSize);
+ ConstDataRangeCursor adc(assocDataCdr);
+
+ uint8_t marker = adc.readAndAdvance<uint8_t>();
+ uassert(6379110,
+ "Invalid data type",
+ static_cast<uint8_t>(EncryptedBinDataType::kFLE2UnindexedEncryptedValue) == marker);
+
+ UUID keyId = UUID::fromCDR(adc.readAndAdvance<UUIDBuf>());
+ auto userKey = keyVault->getUserKeyById(keyId);
+
+ BSONType bsonType = static_cast<BSONType>(adc.read<uint8_t>());
+ uassert(6379111, "Invalid BSON data type", isFLE2UnindexedSupportedType(bsonType));
+
+ auto data = uassertStatusOK(
+ decryptDataWithAssociatedData(userKey.key.toCDR(), assocDataCdr, cipherTextCdr));
+ return {bsonType, data};
+}
+
ESCDerivedFromDataTokenAndContentionFactorToken EDCServerPayloadInfo::getESCToken() const {
return FLETokenFromCDR<FLETokenType::ESCDerivedFromDataTokenAndContentionFactorToken>(
payload.getEscDerivedToken());