@@ -76,6 +76,189 @@ func TestClientSideEncryptionProse(t *testing.T) {
76
76
},
77
77
}
78
78
79
+ runOpts := mtest .NewOptions ().MinServerVersion ("6.0" ).Topologies (mtest .ReplicaSet , mtest .LoadBalanced , mtest .ShardedReplicaSet )
80
+ mt .RunOpts ("explicit encryption" , runOpts , func (mt * mtest.T ) {
81
+ // Test Setup ... begin
82
+ encryptedFields := readJSONFile (mt , "encrypted-fields.json" )
83
+ key1Document := readJSONFile (mt , "key1-document.json" )
84
+ var key1ID primitive.Binary
85
+ {
86
+ subtype , data := key1Document .Lookup ("_id" ).Binary ()
87
+ key1ID = primitive.Binary {Subtype : subtype , Data : data }
88
+ }
89
+
90
+ testSetup := func () (* mongo.Client , * mongo.ClientEncryption ) {
91
+ mtest .DropEncryptedCollection (mt , mt .Client .Database ("db" ).Collection ("explicit_encryption" ), encryptedFields )
92
+ cco := options .CreateCollection ().SetEncryptedFields (encryptedFields )
93
+ err := mt .Client .Database ("db" ).CreateCollection (context .Background (), "explicit_encryption" , cco )
94
+ assert .Nil (mt , err , "error on CreateCollection: %v" , err )
95
+ err = mt .Client .Database ("keyvault" ).Collection ("datakeys" ).Drop (context .Background ())
96
+ assert .Nil (mt , err , "error on Drop: %v" , err )
97
+ keyVaultClient , err := mongo .Connect (context .TODO (), options .Client ().ApplyURI (mtest .ClusterURI ()))
98
+ assert .Nil (mt , err , "error on Connect: %v" , err )
99
+ datakeysColl := keyVaultClient .Database ("keyvault" ).Collection ("datakeys" , options .Collection ().SetWriteConcern (mtest .MajorityWc ))
100
+ _ , err = datakeysColl .InsertOne (context .TODO (), key1Document )
101
+ assert .Nil (mt , err , "error on InsertOne: %v" , err )
102
+ // Create a ClientEncryption.
103
+ ceo := options .ClientEncryption ().
104
+ SetKeyVaultNamespace ("keyvault.datakeys" ).
105
+ SetKmsProviders (fullKmsProvidersMap )
106
+ clientEncryption , err := mongo .NewClientEncryption (keyVaultClient , ceo )
107
+ assert .Nil (mt , err , "error on NewClientEncryption: %v" , err )
108
+
109
+ // Create a MongoClient with AutoEncryptionOpts and bypassQueryAnalysis=true.
110
+ aeo := options .AutoEncryption ().
111
+ SetKeyVaultNamespace ("keyvault.datakeys" ).
112
+ SetKmsProviders (fullKmsProvidersMap ).
113
+ SetBypassQueryAnalysis (true )
114
+ co := options .Client ().SetAutoEncryptionOptions (aeo ).ApplyURI (mtest .ClusterURI ())
115
+ encryptedClient , err := mongo .Connect (context .Background (), co )
116
+ assert .Nil (mt , err , "error on Connect: %v" , err )
117
+ return encryptedClient , clientEncryption
118
+ }
119
+ // Test Setup ... end
120
+
121
+ mt .Run ("case 1: can insert encrypted indexed and find" , func (mt * mtest.T ) {
122
+ encryptedClient , clientEncryption := testSetup ()
123
+ defer clientEncryption .Close (context .Background ())
124
+ defer encryptedClient .Disconnect (context .Background ())
125
+
126
+ // Explicit encrypt the value "encrypted indexed value" with algorithm: "Indexed".
127
+ eo := options .Encrypt ().SetAlgorithm ("Indexed" ).SetKeyID (key1ID )
128
+ valueToEncrypt := "encrypted indexed value"
129
+ rawVal := bson.RawValue {Type : bson .TypeString , Value : bsoncore .AppendString (nil , valueToEncrypt )}
130
+ insertPayload , err := clientEncryption .Encrypt (context .Background (), rawVal , eo )
131
+ assert .Nil (mt , err , "error in Encrypt: %v" , err )
132
+ // Insert.
133
+ coll := encryptedClient .Database ("db" ).Collection ("explicit_encryption" )
134
+ _ , err = coll .InsertOne (context .Background (), bson.D {{"_id" , 1 }, {"encryptedIndexed" , insertPayload }})
135
+ assert .Nil (mt , err , "Error in InsertOne: %v" , err )
136
+ // Explicit encrypt an indexed value to find.
137
+ eo = options .Encrypt ().SetAlgorithm ("Indexed" ).SetKeyID (key1ID ).SetQueryType (options .QueryTypeEquality )
138
+ findPayload , err := clientEncryption .Encrypt (context .Background (), rawVal , eo )
139
+ assert .Nil (mt , err , "error in Encrypt: %v" , err )
140
+ // Find.
141
+ res := coll .FindOne (context .Background (), bson.D {{"encryptedIndexed" , findPayload }})
142
+ assert .Nil (mt , res .Err (), "Error in FindOne: %v" , res .Err ())
143
+ got , err := res .DecodeBytes ()
144
+ assert .Nil (mt , err , "error in DecodeBytes: %v" , err )
145
+ gotValue , err := got .LookupErr ("encryptedIndexed" )
146
+ assert .Nil (mt , err , "error in LookupErr: %v" , err )
147
+ assert .Equal (mt , gotValue .StringValue (), valueToEncrypt , "expected %q, got %q" , valueToEncrypt , gotValue .StringValue ())
148
+ })
149
+ mt .Run ("case 2: can insert encrypted indexed and find with non-zero contention" , func (mt * mtest.T ) {
150
+ encryptedClient , clientEncryption := testSetup ()
151
+ defer clientEncryption .Close (context .Background ())
152
+ defer encryptedClient .Disconnect (context .Background ())
153
+
154
+ coll := encryptedClient .Database ("db" ).Collection ("explicit_encryption" )
155
+ valueToEncrypt := "encrypted indexed value"
156
+ rawVal := bson.RawValue {Type : bson .TypeString , Value : bsoncore .AppendString (nil , valueToEncrypt )}
157
+
158
+ for i := 0 ; i < 10 ; i ++ {
159
+ // Explicit encrypt the value "encrypted indexed value" with algorithm: "Indexed".
160
+ eo := options .Encrypt ().SetAlgorithm ("Indexed" ).SetKeyID (key1ID ).SetContentionFactor (10 )
161
+ insertPayload , err := clientEncryption .Encrypt (context .Background (), rawVal , eo )
162
+ assert .Nil (mt , err , "error in Encrypt: %v" , err )
163
+ // Insert.
164
+ _ , err = coll .InsertOne (context .Background (), bson.D {{"_id" , i }, {"encryptedIndexed" , insertPayload }})
165
+ assert .Nil (mt , err , "Error in InsertOne: %v" , err )
166
+ }
167
+
168
+ // Explicit encrypt an indexed value to find with default contentionFactor 0.
169
+ {
170
+ eo := options .Encrypt ().SetAlgorithm ("Indexed" ).SetKeyID (key1ID ).SetQueryType (options .QueryTypeEquality )
171
+ findPayload , err := clientEncryption .Encrypt (context .Background (), rawVal , eo )
172
+ assert .Nil (mt , err , "error in Encrypt: %v" , err )
173
+ // Find with contentionFactor=0.
174
+ cursor , err := coll .Find (context .Background (), bson.D {{"encryptedIndexed" , findPayload }})
175
+ assert .Nil (mt , err , "error in Find: %v" , err )
176
+ var got []bson.Raw
177
+ err = cursor .All (context .Background (), & got )
178
+ assert .Nil (mt , err , "error in All: %v" , err )
179
+ assert .True (mt , len (got ) < 10 , "expected len(got) < 10, got: %v" , len (got ))
180
+ for _ , doc := range got {
181
+ gotValue , err := doc .LookupErr ("encryptedIndexed" )
182
+ assert .Nil (mt , err , "error in LookupErr: %v" , err )
183
+ assert .Equal (mt , gotValue .StringValue (), valueToEncrypt , "expected %q, got %q" , valueToEncrypt , gotValue .StringValue ())
184
+ }
185
+ }
186
+
187
+ // Explicit encrypt an indexed value to find with contentionFactor 10.
188
+ {
189
+ eo := options .Encrypt ().SetAlgorithm ("Indexed" ).SetKeyID (key1ID ).SetQueryType (options .QueryTypeEquality ).SetContentionFactor (10 )
190
+ findPayload2 , err := clientEncryption .Encrypt (context .Background (), rawVal , eo )
191
+ assert .Nil (mt , err , "error in Encrypt: %v" , err )
192
+ // Find with contentionFactor=10.
193
+ cursor , err := coll .Find (context .Background (), bson.D {{"encryptedIndexed" , findPayload2 }})
194
+ assert .Nil (mt , err , "error in Find: %v" , err )
195
+ var got []bson.Raw
196
+ err = cursor .All (context .Background (), & got )
197
+ assert .Nil (mt , err , "error in All: %v" , err )
198
+ assert .True (mt , len (got ) == 10 , "expected len(got) == 10, got: %v" , len (got ))
199
+ for _ , doc := range got {
200
+ gotValue , err := doc .LookupErr ("encryptedIndexed" )
201
+ assert .Nil (mt , err , "error in LookupErr: %v" , err )
202
+ assert .Equal (mt , gotValue .StringValue (), valueToEncrypt , "expected %q, got %q" , valueToEncrypt , gotValue .StringValue ())
203
+ }
204
+ }
205
+ })
206
+ mt .Run ("case 3: can insert encrypted unindexed" , func (mt * mtest.T ) {
207
+ encryptedClient , clientEncryption := testSetup ()
208
+ defer clientEncryption .Close (context .Background ())
209
+ defer encryptedClient .Disconnect (context .Background ())
210
+
211
+ // Explicit encrypt the value "encrypted indexed value" with algorithm: "Indexed".
212
+ eo := options .Encrypt ().SetAlgorithm ("Unindexed" ).SetKeyID (key1ID )
213
+ valueToEncrypt := "encrypted unindexed value"
214
+ rawVal := bson.RawValue {Type : bson .TypeString , Value : bsoncore .AppendString (nil , valueToEncrypt )}
215
+ insertPayload , err := clientEncryption .Encrypt (context .Background (), rawVal , eo )
216
+ assert .Nil (mt , err , "error in Encrypt: %v" , err )
217
+ // Insert.
218
+ coll := encryptedClient .Database ("db" ).Collection ("explicit_encryption" )
219
+ _ , err = coll .InsertOne (context .Background (), bson.D {{"_id" , 1 }, {"encryptedUnindexed" , insertPayload }})
220
+ assert .Nil (mt , err , "Error in InsertOne: %v" , err )
221
+ // Find.
222
+ res := coll .FindOne (context .Background (), bson.D {{"_id" , 1 }})
223
+ assert .Nil (mt , res .Err (), "Error in FindOne: %v" , res .Err ())
224
+ got , err := res .DecodeBytes ()
225
+ assert .Nil (mt , err , "error in DecodeBytes: %v" , err )
226
+ gotValue , err := got .LookupErr ("encryptedUnindexed" )
227
+ assert .Nil (mt , err , "error in LookupErr: %v" , err )
228
+ assert .Equal (mt , gotValue .StringValue (), valueToEncrypt , "expected %q, got %q" , valueToEncrypt , gotValue .StringValue ())
229
+ })
230
+ mt .Run ("case 4: can roundtrip encrypted indexed" , func (mt * mtest.T ) {
231
+ encryptedClient , clientEncryption := testSetup ()
232
+ defer clientEncryption .Close (context .Background ())
233
+ defer encryptedClient .Disconnect (context .Background ())
234
+
235
+ // Explicit encrypt the value "encrypted indexed value" with algorithm: "Indexed".
236
+ eo := options .Encrypt ().SetAlgorithm ("Indexed" ).SetKeyID (key1ID )
237
+ valueToEncrypt := "encrypted indexed value"
238
+ rawVal := bson.RawValue {Type : bson .TypeString , Value : bsoncore .AppendString (nil , valueToEncrypt )}
239
+ payload , err := clientEncryption .Encrypt (context .Background (), rawVal , eo )
240
+ assert .Nil (mt , err , "error in Encrypt: %v" , err )
241
+ gotValue , err := clientEncryption .Decrypt (context .Background (), payload )
242
+ assert .Nil (mt , err , "error in Decrypt: %v" , err )
243
+ assert .Equal (mt , gotValue .StringValue (), valueToEncrypt , "expected %q, got %q" , valueToEncrypt , gotValue .StringValue ())
244
+ })
245
+ mt .Run ("case 5: can roundtrip encrypted unindexed" , func (mt * mtest.T ) {
246
+ encryptedClient , clientEncryption := testSetup ()
247
+ defer clientEncryption .Close (context .Background ())
248
+ defer encryptedClient .Disconnect (context .Background ())
249
+
250
+ // Explicit encrypt the value "encrypted indexed value" with algorithm: "Indexed".
251
+ eo := options .Encrypt ().SetAlgorithm ("Unindexed" ).SetKeyID (key1ID )
252
+ valueToEncrypt := "encrypted unindexed value"
253
+ rawVal := bson.RawValue {Type : bson .TypeString , Value : bsoncore .AppendString (nil , valueToEncrypt )}
254
+ payload , err := clientEncryption .Encrypt (context .Background (), rawVal , eo )
255
+ assert .Nil (mt , err , "error in Encrypt: %v" , err )
256
+ gotValue , err := clientEncryption .Decrypt (context .Background (), payload )
257
+ assert .Nil (mt , err , "error in Decrypt: %v" , err )
258
+ assert .Equal (mt , gotValue .StringValue (), valueToEncrypt , "expected %q, got %q" , valueToEncrypt , gotValue .StringValue ())
259
+ })
260
+ })
261
+
79
262
mt .RunOpts ("data key and double encryption" , noClientOpts , func (mt * mtest.T ) {
80
263
// set up options structs
81
264
schema := bson.D {
0 commit comments