Skip to content

Commit 60ff1cc

Browse files
authored
CSHARP-4669: Mitigated clientEncrytion.Encrypt using a lot of memory (#1173)
1 parent f7e5a31 commit 60ff1cc

File tree

4 files changed

+49
-9
lines changed

4 files changed

+49
-9
lines changed

src/MongoDB.Bson/BsonExtensionMethods.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,19 @@ public static class BsonExtensionMethods
3434
/// <param name="writerSettings">The writer settings.</param>
3535
/// <param name="configurator">The serialization context configurator.</param>
3636
/// <param name="args">The serialization args.</param>
37+
/// <param name="estimatedBsonSize">The estimated size of the serialized object</param>
3738
/// <returns>A BSON byte array.</returns>
3839
public static byte[] ToBson<TNominalType>(
3940
this TNominalType obj,
4041
IBsonSerializer<TNominalType> serializer = null,
4142
BsonBinaryWriterSettings writerSettings = null,
4243
Action<BsonSerializationContext.Builder> configurator = null,
43-
BsonSerializationArgs args = default(BsonSerializationArgs)
44-
)
44+
BsonSerializationArgs args = default(BsonSerializationArgs),
45+
int estimatedBsonSize = 0)
4546
{
4647
args.SetOrValidateNominalType(typeof(TNominalType), "<TNominalType>");
47-
return ToBson(obj, typeof(TNominalType), writerSettings, serializer, configurator, args);
48+
49+
return ToBson(obj, typeof(TNominalType), writerSettings, serializer, configurator, args, estimatedBsonSize);
4850
}
4951

5052
/// <summary>
@@ -56,6 +58,7 @@ public static byte[] ToBson<TNominalType>(
5658
/// <param name="serializer">The serializer.</param>
5759
/// <param name="configurator">The serialization context configurator.</param>
5860
/// <param name="args">The serialization args.</param>
61+
/// <param name="estimatedBsonSize">The estimated size of the serialized object.</param>
5962
/// <returns>A BSON byte array.</returns>
6063
/// <exception cref="System.ArgumentNullException">nominalType</exception>
6164
/// <exception cref="System.ArgumentException">serializer</exception>
@@ -65,8 +68,14 @@ public static byte[] ToBson(
6568
BsonBinaryWriterSettings writerSettings = null,
6669
IBsonSerializer serializer = null,
6770
Action<BsonSerializationContext.Builder> configurator = null,
68-
BsonSerializationArgs args = default(BsonSerializationArgs))
71+
BsonSerializationArgs args = default(BsonSerializationArgs),
72+
int estimatedBsonSize = 0)
6973
{
74+
if (estimatedBsonSize < 0)
75+
{
76+
throw new ArgumentException("Value cannot be negative.", nameof(estimatedBsonSize));
77+
}
78+
7079
if (nominalType == null)
7180
{
7281
throw new ArgumentNullException("nominalType");
@@ -83,7 +92,7 @@ public static byte[] ToBson(
8392
throw new ArgumentException(message, "serializer");
8493
}
8594

86-
using (var memoryStream = new MemoryStream())
95+
using (var memoryStream = new MemoryStream(estimatedBsonSize))
8796
{
8897
using (var bsonWriter = new BsonBinaryWriter(memoryStream, writerSettings ?? BsonBinaryWriterSettings.Defaults))
8998
{

src/MongoDB.Driver/Encryption/ExplicitEncryptionLibMongoCryptController.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ namespace MongoDB.Driver.Encryption
2727
{
2828
internal sealed class ExplicitEncryptionLibMongoCryptController : LibMongoCryptControllerBase
2929
{
30+
private const int BufferOverhead = 32; // fixed overhead added when serializing BsonDocument with BsonBinaryData Object
31+
3032
// constructors
3133
public ExplicitEncryptionLibMongoCryptController(
3234
CryptClient cryptClient,
@@ -541,7 +543,11 @@ private KmsKeyId GetKmsKeyId(string kmsProvider, DataKeyOptions dataKeyOptions)
541543

542544
private byte[] GetWrappedAlternateKeyNameBytes(string value) => !string.IsNullOrWhiteSpace(value) ? ToBsonIfNotNull(new BsonDocument("keyAltName", value)) : null;
543545

544-
private byte[] GetWrappedValueBytes(BsonValue value) => ToBsonIfNotNull(new BsonDocument("v", value));
546+
private byte[] GetWrappedValueBytes(BsonValue value)
547+
{
548+
var estimatedSize = (value is BsonBinaryData binaryData) ? binaryData.Bytes.Length + BufferOverhead : 0;
549+
return ToBsonIfNotNull(new BsonDocument("v", value), estimatedSize);
550+
}
545551

546552
private BsonValue RenderFilter(FilterDefinition<BsonDocument> filter)
547553
{

src/MongoDB.Driver/Encryption/LibMongoCryptControllerBase.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ protected async Task<byte[]> ProcessStatesAsync(CryptContext context, string dat
166166
return result;
167167
}
168168

169-
protected byte[] ToBsonIfNotNull(BsonValue value)
169+
protected byte[] ToBsonIfNotNull(BsonValue value, int estimatedBsonSize = 0)
170170
{
171171
if (value != null)
172172
{
@@ -177,9 +177,8 @@ protected byte[] ToBsonIfNotNull(BsonValue value)
177177
writerSettings.GuidRepresentation = GuidRepresentation.Unspecified;
178178
}
179179
#pragma warning restore 618
180-
return value.ToBson(writerSettings: writerSettings);
180+
return value.ToBson(writerSettings: writerSettings, estimatedBsonSize: estimatedBsonSize);
181181
}
182-
183182
return null;
184183
}
185184

tests/MongoDB.Bson.Tests/BsonExtensionMethodsTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
1313
* limitations under the License.
1414
*/
1515

16+
using System;
1617
using System.Linq;
18+
using FluentAssertions;
1719
using MongoDB.Bson;
1820
using MongoDB.Bson.Serialization;
21+
using MongoDB.TestHelpers.XunitExtensions;
1922
using Xunit;
2023

2124
namespace MongoDB.Bson.Tests
@@ -55,6 +58,29 @@ public void TestToBsonIdFirst()
5558
Assert.True(expected.SequenceEqual(bson));
5659
}
5760

61+
[Fact]
62+
public void TestToBsonWithBadEstimatedBsonSizeShouldThrowException()
63+
{
64+
var document = new BsonDocument();
65+
var exception = Record.Exception(() => document.ToBson(estimatedBsonSize: -1));
66+
var e = exception.Should().BeOfType<ArgumentException>().Subject;
67+
e.ParamName.Should().Be("estimatedBsonSize");
68+
e.Message.Should().StartWith("Value cannot be negative");
69+
}
70+
71+
[Theory]
72+
[InlineData(13, new byte[] {}, new byte[] { 13, 0, 0, 0, 5, 118, 0, 0, 0, 0, 0, 0, 0 })]
73+
[InlineData(18, new byte[] { 1, 2, 3, 4, 5}, new byte[] { 18, 0, 0, 0, 5, 118, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0 })]
74+
[InlineData(32, new byte[] { 1, 2, 3, 4, 5}, new byte[] { 18, 0, 0, 0, 5, 118, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0 })]
75+
[InlineData(12, new byte[] { 1, 2, 3, 4, 5}, new byte[] { 18, 0, 0, 0, 5, 118, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0 })]
76+
[InlineData(0, new byte[] { 1, 2, 3, 4, 5}, new byte[] { 18, 0, 0, 0, 5, 118, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0 })]
77+
public void TestToBsonWithNonZeroEstimatedBsonSize(int estimatedBsonSize, byte[] data, byte[] expectedBson)
78+
{
79+
var document = new BsonDocument("v", new BsonBinaryData(data));
80+
var bson = document.ToBson(estimatedBsonSize: estimatedBsonSize);
81+
Assert.True(bson.SequenceEqual(expectedBson));
82+
}
83+
5884
[Fact]
5985
public void TestToBsonDocumentEmptyDocument()
6086
{

0 commit comments

Comments
 (0)