1
2
3
4
5
6
7
8
9
10 package integration
11
12 import (
13 "context"
14 "crypto/tls"
15 "encoding/base64"
16 "fmt"
17 "io/ioutil"
18 "net"
19 "net/http"
20 "os"
21 "path/filepath"
22 "strings"
23 "testing"
24 "time"
25
26 "go.mongodb.org/mongo-driver/bson"
27 "go.mongodb.org/mongo-driver/bson/bsontype"
28 "go.mongodb.org/mongo-driver/bson/primitive"
29 "go.mongodb.org/mongo-driver/event"
30 "go.mongodb.org/mongo-driver/internal/assert"
31 "go.mongodb.org/mongo-driver/internal/handshake"
32 "go.mongodb.org/mongo-driver/internal/integtest"
33 "go.mongodb.org/mongo-driver/mongo"
34 "go.mongodb.org/mongo-driver/mongo/integration/mtest"
35 "go.mongodb.org/mongo-driver/mongo/options"
36 "go.mongodb.org/mongo-driver/mongo/writeconcern"
37 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
38 "go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt"
39 mongocryptopts "go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/options"
40 )
41
42 var (
43 localMasterKey = []byte("2x44+xduTaBBkY16Er5DuADaghvS4vwdkg8tpPp3tz6gV01A1CwbD9itQ2HFDgPWOp8eMaC1Oi766JzXZBdBdbdMurdonJ1d")
44 )
45
46 const (
47 clientEncryptionProseDir = "../../testdata/client-side-encryption-prose"
48 deterministicAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
49 randomAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
50 kvNamespace = "keyvault.datakeys"
51 keySubtype byte = 4
52 encryptedValueSubtype byte = 6
53 cryptMaxBatchSizeBytes = 2097152
54 maxBsonObjSize = 16777216
55 )
56
57 func containsSubstring(possibleSubstrings []string, str string) bool {
58 for _, possibleSubstring := range possibleSubstrings {
59 if strings.Contains(str, possibleSubstring) {
60 return true
61 }
62 }
63
64 return false
65 }
66
67 func TestClientSideEncryptionProse(t *testing.T) {
68 t.Parallel()
69
70 verifyClientSideEncryptionVarsSet(t)
71 mt := mtest.New(t, mtest.NewOptions().MinServerVersion("4.2").Enterprise(true).CreateClient(false))
72
73 defaultKvClientOptions := options.Client().ApplyURI(mtest.ClusterURI())
74 integtest.AddTestServerAPIVersion(defaultKvClientOptions)
75 fullKmsProvidersMap := map[string]map[string]interface{}{
76 "aws": {
77 "accessKeyId": awsAccessKeyID,
78 "secretAccessKey": awsSecretAccessKey,
79 },
80 "azure": {
81 "tenantId": azureTenantID,
82 "clientId": azureClientID,
83 "clientSecret": azureClientSecret,
84 },
85 "gcp": {
86 "email": gcpEmail,
87 "privateKey": gcpPrivateKey,
88 },
89 "local": {"key": localMasterKey},
90 "kmip": {
91 "endpoint": "localhost:5698",
92 },
93 }
94
95 mt.Run("1. custom key material test", func(mt *mtest.T) {
96 const (
97 dkCollection = "datakeys"
98 idKey = "_id"
99 kvDatabase = "keyvault"
100 )
101
102
103
104 cse := setup(mt, nil, defaultKvClientOptions, options.ClientEncryption().
105 SetKmsProviders(fullKmsProvidersMap).
106 SetKeyVaultNamespace(kvNamespace))
107
108 err := cse.kvClient.Database(kvDatabase).Collection(dkCollection).Drop(context.Background())
109 assert.Nil(mt, err, "error dropping %q namespace: %v", kvNamespace, err)
110
111
112
113 const b641 = `xPTAjBRG5JiPm+d3fj6XLi2q5DMXUS/f1f+SMAlhhwkhDRL0kr8r9GDLIGTAGlvC+HVjSIgdL+RKwZCvpXSyxTICWSXT` +
114 `UYsWYPyu3IoHbuBZdmw2faM3WhcRIgbMReU5`
115
116
117 km, err := base64.StdEncoding.DecodeString(b641)
118 assert.Nil(mt, err, "error decoding b64: %v", err)
119
120 _, err = cse.clientEnc.CreateDataKey(context.Background(), "local", options.DataKey().SetKeyMaterial(km))
121 assert.Nil(mt, err, "error creating data key: %v", err)
122
123
124
125 coll := cse.kvClient.Database(kvDatabase).Collection(dkCollection)
126
127 keydoc, err := coll.FindOne(context.Background(), bson.D{}).Raw()
128 assert.Nil(mt, err, "error in decoding bytes: %v", err)
129
130
131 id, err := keydoc.LookupErr(idKey)
132 assert.Nil(mt, err, "error looking up %s: %v", idKey, err)
133
134 _, err = coll.DeleteOne(context.Background(), bson.D{{idKey, id}})
135 assert.Nil(mt, err, "error deleting key document: %v", err)
136
137
138
139
140 cidx, alteredKeydoc := bsoncore.AppendDocumentStart(nil)
141 docElems, _ := keydoc.Elements()
142 for _, element := range docElems {
143 if key := element.Key(); key != idKey {
144 alteredKeydoc = bsoncore.AppendValueElement(alteredKeydoc, key, rawValueToCoreValue(element.Value()))
145 }
146 }
147 empty := [16]byte{}
148 uuidSubtype, _ := keydoc.Lookup(idKey).Binary()
149 alteredKeydoc = bsoncore.AppendBinaryElement(alteredKeydoc, idKey, uuidSubtype, empty[:])
150 alteredKeydoc, _ = bsoncore.AppendDocumentEnd(alteredKeydoc, cidx)
151
152
153 wcMajority := writeconcern.New(writeconcern.WMajority(), writeconcern.WTimeout(1*time.Second))
154 wcMajorityCollectionOpts := options.Collection().SetWriteConcern(wcMajority)
155 wcmColl := cse.kvClient.Database(kvDatabase).Collection(dkCollection, wcMajorityCollectionOpts)
156 _, err = wcmColl.InsertOne(context.Background(), alteredKeydoc)
157 assert.Nil(mt, err, "error inserting altered key document: %v", err)
158
159
160
161
162 const b642 = `AQAAAAAAAAAAAAAAAAAAAAACz0ZOLuuhEYi807ZXTdhbqhLaS2/t9wLifJnnNYwiw79d75QYIZ6M/aYC1h9nCzCjZ7pG` +
163 `UpAuNnkUhnIXM3PjrA==`
164
165 empty = [16]byte{}
166 keyid := primitive.Binary{Subtype: 0x04, Data: empty[:]}
167
168 encOpts := options.Encrypt().SetAlgorithm(deterministicAlgorithm).SetKeyID(keyid)
169 testVal := bson.RawValue{
170 Type: bson.TypeString,
171 Value: bsoncore.AppendString(nil, "test"),
172 }
173 actual, err := cse.clientEnc.Encrypt(context.Background(), testVal, encOpts)
174 assert.Nil(mt, err, "error encrypting data: %v", err)
175
176 expected := primitive.Binary{Subtype: 0x06}
177 expected.Data, _ = base64.StdEncoding.DecodeString(b642)
178
179 assert.Equal(t, actual, expected, "expected: %v, got: %v", actual, expected)
180 })
181 mt.RunOpts("2. data key and double encryption", noClientOpts, func(mt *mtest.T) {
182
183 schema := bson.D{
184 {"bsonType", "object"},
185 {"properties", bson.D{
186 {"encrypted_placeholder", bson.D{
187 {"encrypt", bson.D{
188 {"keyId", "/placeholder"},
189 {"bsonType", "string"},
190 {"algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Random"},
191 }},
192 }},
193 }},
194 }
195 schemaMap := map[string]interface{}{"db.coll": schema}
196 tlsConfig := make(map[string]*tls.Config)
197 if tlsCAFileKMIP != "" && tlsClientCertificateKeyFileKMIP != "" {
198 tlsOpts := map[string]interface{}{
199 "tlsCertificateKeyFile": tlsClientCertificateKeyFileKMIP,
200 "tlsCAFile": tlsCAFileKMIP,
201 }
202 kmipConfig, err := options.BuildTLSConfig(tlsOpts)
203 assert.Nil(mt, err, "BuildTLSConfig error: %v", err)
204 tlsConfig["kmip"] = kmipConfig
205 }
206
207 aeo := options.AutoEncryption().
208 SetKmsProviders(fullKmsProvidersMap).
209 SetKeyVaultNamespace(kvNamespace).
210 SetSchemaMap(schemaMap).
211 SetTLSConfig(tlsConfig).
212 SetExtraOptions(getCryptSharedLibExtraOptions())
213
214 ceo := options.ClientEncryption().
215 SetKmsProviders(fullKmsProvidersMap).
216 SetKeyVaultNamespace(kvNamespace).
217 SetTLSConfig(tlsConfig)
218
219 awsMasterKey := bson.D{
220 {"region", "us-east-1"},
221 {"key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0"},
222 }
223 azureMasterKey := bson.D{
224 {"keyVaultEndpoint", "key-vault-csfle.vault.azure.net"},
225 {"keyName", "key-name-csfle"},
226 }
227 gcpMasterKey := bson.D{
228 {"projectId", "devprod-drivers"},
229 {"location", "global"},
230 {"keyRing", "key-ring-csfle"},
231 {"keyName", "key-name-csfle"},
232 }
233 kmipMasterKey := bson.D{}
234 testCases := []struct {
235 provider string
236 masterKey interface{}
237 }{
238 {"local", nil},
239 {"aws", awsMasterKey},
240 {"azure", azureMasterKey},
241 {"gcp", gcpMasterKey},
242 {"kmip", kmipMasterKey},
243 }
244 for _, tc := range testCases {
245 mt.Run(tc.provider, func(mt *mtest.T) {
246 if tc.provider == "kmip" && "" == os.Getenv("KMS_MOCK_SERVERS_RUNNING") {
247 mt.Skipf("Skipping test as KMS_MOCK_SERVERS_RUNNING is not set")
248 }
249 var startedEvents []*event.CommandStartedEvent
250 monitor := &event.CommandMonitor{
251 Started: func(_ context.Context, evt *event.CommandStartedEvent) {
252 startedEvents = append(startedEvents, evt)
253 },
254 }
255 kvClientOpts := options.Client().ApplyURI(mtest.ClusterURI()).SetMonitor(monitor)
256 integtest.AddTestServerAPIVersion(kvClientOpts)
257 cpt := setup(mt, aeo, kvClientOpts, ceo)
258 defer cpt.teardown(mt)
259
260
261 keyAltName := fmt.Sprintf("%s_altname", tc.provider)
262 dataKeyOpts := options.DataKey().SetKeyAltNames([]string{keyAltName})
263 if tc.masterKey != nil {
264 dataKeyOpts.SetMasterKey(tc.masterKey)
265 }
266 dataKeyID, err := cpt.clientEnc.CreateDataKey(context.Background(), tc.provider, dataKeyOpts)
267 assert.Nil(mt, err, "CreateDataKey error: %v", err)
268 assert.Equal(mt, keySubtype, dataKeyID.Subtype,
269 "expected data key subtype %v, got %v", keySubtype, dataKeyID.Subtype)
270
271
272 cursor, err := cpt.keyVaultColl.Find(context.Background(), bson.D{{"_id", dataKeyID}})
273 assert.Nil(mt, err, "key vault Find error: %v", err)
274 assert.True(mt, cursor.Next(context.Background()), "no keys found in key vault")
275 provider := cursor.Current.Lookup("masterKey", "provider").StringValue()
276 assert.Equal(mt, tc.provider, provider, "expected provider %v, got %v", tc.provider, provider)
277 assert.False(mt, cursor.Next(context.Background()), "unexpected document in key vault: %v", cursor.Current)
278
279
280 assert.Equal(mt, 1, len(startedEvents), "expected 1 CommandStartedEvent, got %v", len(startedEvents))
281 evt := startedEvents[0]
282 assert.Equal(mt, "insert", evt.CommandName, "expected command 'insert', got '%v'", evt.CommandName)
283 writeConcernVal, err := evt.Command.LookupErr("writeConcern")
284 assert.Nil(mt, err, "expected writeConcern in command %s", evt.Command)
285 wString := writeConcernVal.Document().Lookup("w").StringValue()
286 assert.Equal(mt, "majority", wString, "expected write concern 'majority', got %v", wString)
287
288
289 valueToEncrypt := fmt.Sprintf("hello %s", tc.provider)
290 rawVal := bson.RawValue{Type: bson.TypeString, Value: bsoncore.AppendString(nil, valueToEncrypt)}
291 encrypted, err := cpt.clientEnc.Encrypt(context.Background(), rawVal,
292 options.Encrypt().SetAlgorithm(deterministicAlgorithm).SetKeyID(dataKeyID))
293 assert.Nil(mt, err, "Encrypt error while encrypting value by ID: %v", err)
294 assert.Equal(mt, encryptedValueSubtype, encrypted.Subtype,
295 "expected encrypted value subtype %v, got %v", encryptedValueSubtype, encrypted.Subtype)
296
297
298 _, err = cpt.cseColl.InsertOne(context.Background(), bson.D{{"_id", tc.provider}, {"value", encrypted}})
299 assert.Nil(mt, err, "InsertOne error: %v", err)
300
301
302 resBytes, err := cpt.cseColl.FindOne(context.Background(), bson.D{{"_id", tc.provider}}).Raw()
303 assert.Nil(mt, err, "Find error: %v", err)
304 foundVal := resBytes.Lookup("value").StringValue()
305 assert.Equal(mt, valueToEncrypt, foundVal, "expected value %v, got %v", valueToEncrypt, foundVal)
306
307
308 altEncrypted, err := cpt.clientEnc.Encrypt(context.Background(), rawVal,
309 options.Encrypt().SetAlgorithm(deterministicAlgorithm).SetKeyAltName(keyAltName))
310 assert.Nil(mt, err, "Encrypt error while encrypting value by alt key name: %v", err)
311 assert.Equal(mt, encryptedValueSubtype, altEncrypted.Subtype,
312 "expected encrypted value subtype %v, got %v", encryptedValueSubtype, altEncrypted.Subtype)
313 assert.Equal(mt, encrypted.Data, altEncrypted.Data,
314 "expected data %v, got %v", encrypted.Data, altEncrypted.Data)
315
316
317 _, err = cpt.cseColl.InsertOne(context.Background(), bson.D{{"encrypted_placeholder", encrypted}})
318 assert.NotNil(mt, err, "expected InsertOne error, got nil")
319 })
320 }
321 })
322 mt.RunOpts("3. external key vault", noClientOpts, func(mt *mtest.T) {
323 testCases := []struct {
324 name string
325 externalVault bool
326 }{
327 {"with external vault", true},
328 {"without external vault", false},
329 }
330
331 for _, tc := range testCases {
332 mt.Run(tc.name, func(mt *mtest.T) {
333
334 kmsProviders := map[string]map[string]interface{}{
335 "local": {
336 "key": localMasterKey,
337 },
338 }
339 schemaMap := map[string]interface{}{"db.coll": readJSONFile(mt, "external-schema.json")}
340 aeo := options.AutoEncryption().
341 SetKmsProviders(kmsProviders).
342 SetKeyVaultNamespace(kvNamespace).
343 SetSchemaMap(schemaMap).
344 SetExtraOptions(getCryptSharedLibExtraOptions())
345 ceo := options.ClientEncryption().
346 SetKmsProviders(kmsProviders).
347 SetKeyVaultNamespace(kvNamespace)
348 kvClientOpts := defaultKvClientOptions
349
350 if tc.externalVault {
351 externalKvOpts := options.Client().ApplyURI(mtest.ClusterURI()).SetAuth(options.Credential{
352 Username: "fake-user",
353 Password: "fake-password",
354 })
355 integtest.AddTestServerAPIVersion(externalKvOpts)
356 aeo.SetKeyVaultClientOptions(externalKvOpts)
357 kvClientOpts = externalKvOpts
358 }
359 cpt := setup(mt, aeo, kvClientOpts, ceo)
360 defer cpt.teardown(mt)
361
362
363 key := readJSONFile(mt, "external-key.json")
364 _, err := cpt.keyVaultColl.InsertOne(context.Background(), key)
365 assert.Nil(mt, err, "InsertOne error for data key: %v", err)
366 subtype, data := key.Lookup("_id").Binary()
367 dataKeyID := primitive.Binary{Subtype: subtype, Data: data}
368
369 doc := bson.D{{"encrypted", "test"}}
370 _, insertErr := cpt.cseClient.Database("db").Collection("coll").InsertOne(context.Background(), doc)
371 rawVal := bson.RawValue{Type: bson.TypeString, Value: bsoncore.AppendString(nil, "test")}
372 _, encErr := cpt.clientEnc.Encrypt(context.Background(), rawVal,
373 options.Encrypt().SetKeyID(dataKeyID).SetAlgorithm(deterministicAlgorithm))
374
375 if tc.externalVault {
376 assert.NotNil(mt, insertErr, "expected InsertOne auth error, got nil")
377 assert.NotNil(mt, encErr, "expected Encrypt auth error, got nil")
378 assert.True(mt, strings.Contains(insertErr.Error(), "auth error"),
379 "expected InsertOne auth error, got %v", insertErr)
380 assert.True(mt, strings.Contains(encErr.Error(), "auth error"),
381 "expected Encrypt auth error, got %v", insertErr)
382 return
383 }
384 assert.Nil(mt, insertErr, "InsertOne error: %v", insertErr)
385 assert.Nil(mt, encErr, "Encrypt error: %v", err)
386 })
387 }
388 })
389 mt.Run("4. bson size limits", func(mt *mtest.T) {
390 kmsProviders := map[string]map[string]interface{}{
391 "local": {
392 "key": localMasterKey,
393 },
394 }
395 aeo := options.AutoEncryption().
396 SetKmsProviders(kmsProviders).
397 SetKeyVaultNamespace(kvNamespace).
398 SetExtraOptions(getCryptSharedLibExtraOptions())
399 cpt := setup(mt, aeo, nil, nil)
400 defer cpt.teardown(mt)
401
402
403 err := mt.Client.Database("db").RunCommand(context.Background(), bson.D{
404 {"create", "coll"},
405 {"validator", bson.D{
406 {"$jsonSchema", readJSONFile(mt, "limits-schema.json")},
407 }},
408 }).Err()
409 assert.Nil(mt, err, "create error with validator: %v", err)
410
411
412 key := readJSONFile(mt, "limits-key.json")
413 _, err = cpt.keyVaultColl.InsertOne(context.Background(), key)
414 assert.Nil(mt, err, "InsertOne error for key: %v", err)
415
416 var builder2mb, builder16mb strings.Builder
417 for i := 0; i < cryptMaxBatchSizeBytes; i++ {
418 builder2mb.WriteByte('a')
419 }
420 for i := 0; i < maxBsonObjSize; i++ {
421 builder16mb.WriteByte('a')
422 }
423 complete2mbStr := builder2mb.String()
424 complete16mbStr := builder16mb.String()
425
426
427 doc := bson.D{{"over_2mib_under_16mib", complete2mbStr}}
428 _, err = cpt.cseColl.InsertOne(context.Background(), doc)
429 assert.Nil(mt, err, "InsertOne error for 2MiB document: %v", err)
430
431 str := complete2mbStr[:cryptMaxBatchSizeBytes-2000]
432 limitsDoc := readJSONFile(mt, "limits-doc.json")
433
434
435 var extendedLimitsDoc []byte
436 extendedLimitsDoc = append(extendedLimitsDoc, limitsDoc...)
437 extendedLimitsDoc = extendedLimitsDoc[:len(extendedLimitsDoc)-1]
438 extendedLimitsDoc = bsoncore.AppendStringElement(extendedLimitsDoc, "_id", "encryption_exceeds_2mib")
439 extendedLimitsDoc = bsoncore.AppendStringElement(extendedLimitsDoc, "unencrypted", str)
440 extendedLimitsDoc, _ = bsoncore.AppendDocumentEnd(extendedLimitsDoc, 0)
441 _, err = cpt.cseColl.InsertOne(context.Background(), extendedLimitsDoc)
442 assert.Nil(mt, err, "error inserting extended limits document: %v", err)
443
444
445
446
447 cpt.cseStarted = cpt.cseStarted[:0]
448 firstDoc := bson.D{{"_id", "over_2mib_1"}, {"unencrypted", complete2mbStr}}
449 secondDoc := bson.D{{"_id", "over_2mib_2"}, {"unencrypted", complete2mbStr}}
450 _, err = cpt.cseColl.InsertMany(context.Background(), []interface{}{firstDoc, secondDoc})
451 assert.Nil(mt, err, "InsertMany error for small documents: %v", err)
452 assert.Equal(mt, 2, len(cpt.cseStarted), "expected 2 insert events, got %d", len(cpt.cseStarted))
453
454
455 str = complete2mbStr[:cryptMaxBatchSizeBytes-20000]
456 firstBulkDoc := make([]byte, len(limitsDoc))
457 copy(firstBulkDoc, limitsDoc)
458 firstBulkDoc = firstBulkDoc[:len(firstBulkDoc)-1]
459 firstBulkDoc = bsoncore.AppendStringElement(firstBulkDoc, "_id", "encryption_exceeds_2mib_1")
460 firstBulkDoc = bsoncore.AppendStringElement(firstBulkDoc, "unencrypted", string(str))
461 firstBulkDoc, _ = bsoncore.AppendDocumentEnd(firstBulkDoc, 0)
462
463 secondBulkDoc := make([]byte, len(limitsDoc))
464 copy(secondBulkDoc, limitsDoc)
465 secondBulkDoc = secondBulkDoc[:len(secondBulkDoc)-1]
466 secondBulkDoc = bsoncore.AppendStringElement(secondBulkDoc, "_id", "encryption_exceeds_2mib_2")
467 secondBulkDoc = bsoncore.AppendStringElement(secondBulkDoc, "unencrypted", string(str))
468 secondBulkDoc, _ = bsoncore.AppendDocumentEnd(secondBulkDoc, 0)
469
470 cpt.cseStarted = cpt.cseStarted[:0]
471 _, err = cpt.cseColl.InsertMany(context.Background(), []interface{}{firstBulkDoc, secondBulkDoc})
472 assert.Nil(mt, err, "InsertMany error for large documents: %v", err)
473 assert.Equal(mt, 2, len(cpt.cseStarted), "expected 2 insert events, got %d", len(cpt.cseStarted))
474
475
476 doc = bson.D{{"_id", "under_16mib"}, {"unencrypted", complete16mbStr[:maxBsonObjSize-2000]}}
477 _, err = cpt.cseColl.InsertOne(context.Background(), doc)
478 assert.Nil(mt, err, "InsertOne error: %v", err)
479
480
481 var over16mb []byte
482 over16mb = append(over16mb, limitsDoc...)
483 over16mb = over16mb[:len(over16mb)-1]
484 over16mb = bsoncore.AppendStringElement(over16mb, "_id", "encryption_exceeds_16mib")
485 over16mb = bsoncore.AppendStringElement(over16mb, "unencrypted", complete16mbStr[:maxBsonObjSize-2000])
486 over16mb, _ = bsoncore.AppendDocumentEnd(over16mb, 0)
487 _, err = cpt.cseColl.InsertOne(context.Background(), over16mb)
488 assert.NotNil(mt, err, "expected InsertOne error for document over 16MiB, got nil")
489 })
490 mt.Run("5. views are prohibited", func(mt *mtest.T) {
491 mt.Parallel()
492
493 kmsProviders := map[string]map[string]interface{}{
494 "local": {
495 "key": localMasterKey,
496 },
497 }
498 aeo := options.AutoEncryption().
499 SetKmsProviders(kmsProviders).
500 SetKeyVaultNamespace(kvNamespace).
501 SetExtraOptions(getCryptSharedLibExtraOptions())
502 cpt := setup(mt, aeo, nil, nil)
503 defer cpt.teardown(mt)
504
505
506 mt.CreateCollection(mtest.Collection{
507 Name: "view",
508 DB: cpt.cseColl.Database().Name(),
509 ViewOn: "coll",
510 ViewPipeline: mongo.Pipeline{},
511 }, true)
512
513 view := cpt.cseColl.Database().Collection("view")
514 _, err := view.InsertOne(context.Background(), bson.D{{"_id", "insert_on_view"}})
515 assert.NotNil(mt, err, "expected InsertOne error on view, got nil")
516 errStr := strings.ToLower(err.Error())
517 viewErrSubstr := "cannot auto encrypt a view"
518 assert.True(mt, strings.Contains(errStr, viewErrSubstr),
519 "expected error '%v' to contain substring '%v'", errStr, viewErrSubstr)
520 })
521 mt.RunOpts("6. corpus test", noClientOpts, func(mt *mtest.T) {
522 if "" == os.Getenv("KMS_MOCK_SERVERS_RUNNING") {
523 mt.Skipf("Skipping test as KMS_MOCK_SERVERS_RUNNING is not set")
524 }
525 corpusSchema := readJSONFile(mt, "corpus-schema.json")
526 localSchemaMap := map[string]interface{}{
527 "db.coll": corpusSchema,
528 }
529
530 tlsConfig := make(map[string]*tls.Config)
531 if tlsCAFileKMIP != "" && tlsClientCertificateKeyFileKMIP != "" {
532 tlsOpts := map[string]interface{}{
533 "tlsCertificateKeyFile": tlsClientCertificateKeyFileKMIP,
534 "tlsCAFile": tlsCAFileKMIP,
535 }
536 kmipConfig, err := options.BuildTLSConfig(tlsOpts)
537 assert.Nil(mt, err, "BuildTLSConfig error: %v", err)
538 tlsConfig["kmip"] = kmipConfig
539 }
540
541 getBaseAutoEncryptionOpts := func() *options.AutoEncryptionOptions {
542 return options.AutoEncryption().
543 SetKmsProviders(fullKmsProvidersMap).
544 SetKeyVaultNamespace(kvNamespace).
545 SetTLSConfig(tlsConfig).
546 SetExtraOptions(getCryptSharedLibExtraOptions())
547 }
548
549 testCases := []struct {
550 name string
551 aeo *options.AutoEncryptionOptions
552 schema bson.Raw
553 }{
554 {"remote schema", getBaseAutoEncryptionOpts(), corpusSchema},
555 {"local schema", getBaseAutoEncryptionOpts().SetSchemaMap(localSchemaMap), nil},
556 }
557
558 for _, tc := range testCases {
559 mt.Run(tc.name, func(mt *mtest.T) {
560 ceo := options.ClientEncryption().
561 SetKmsProviders(fullKmsProvidersMap).
562 SetKeyVaultNamespace(kvNamespace).
563 SetTLSConfig(tlsConfig)
564
565 cpt := setup(mt, tc.aeo, defaultKvClientOptions, ceo)
566 defer cpt.teardown(mt)
567
568
569 if tc.schema != nil {
570 db := cpt.coll.Database()
571 err := db.RunCommand(context.Background(), bson.D{
572 {"create", "coll"},
573 {"validator", bson.D{
574 {"$jsonSchema", readJSONFile(mt, "corpus-schema.json")},
575 }},
576 }).Err()
577 assert.Nil(mt, err, "create error with validator: %v", err)
578 }
579
580
581 _, err := cpt.keyVaultColl.InsertMany(context.Background(), []interface{}{
582 readJSONFile(mt, "corpus-key-local.json"),
583 readJSONFile(mt, "corpus-key-aws.json"),
584 readJSONFile(mt, "corpus-key-azure.json"),
585 readJSONFile(mt, "corpus-key-gcp.json"),
586 readJSONFile(mt, "corpus-key-kmip.json"),
587 })
588 assert.Nil(mt, err, "InsertMany error for key vault: %v", err)
589
590
591
592 corpus := readJSONFile(mt, "corpus.json")
593 cidx, copied := bsoncore.AppendDocumentStart(nil)
594 elems, _ := corpus.Elements()
595
596
597 copiedKeys := map[string]struct{}{
598 "_id": {},
599 "altname_aws": {},
600 "altname_local": {},
601 "altname_azure": {},
602 "altname_gcp": {},
603 "altname_kmip": {},
604 }
605
606 for _, elem := range elems {
607 key := elem.Key()
608 val := elem.Value()
609
610 if _, ok := copiedKeys[key]; ok {
611 copied = bsoncore.AppendStringElement(copied, key, val.StringValue())
612 continue
613 }
614
615 doc := val.Document()
616 switch method := doc.Lookup("method").StringValue(); method {
617 case "auto":
618
619 copied = bsoncore.AppendDocumentElement(copied, key, doc)
620 continue
621 case "explicit":
622
623 default:
624 mt.Fatalf("unrecognized 'method' value %q", method)
625 }
626
627
628 algorithm := deterministicAlgorithm
629 if doc.Lookup("algo").StringValue() == "rand" {
630 algorithm = randomAlgorithm
631 }
632 eo := options.Encrypt().SetAlgorithm(algorithm)
633
634 identifier := doc.Lookup("identifier").StringValue()
635 kms := doc.Lookup("kms").StringValue()
636 switch identifier {
637 case "id":
638 var keyID string
639 switch kms {
640 case "local":
641 keyID = "LOCALAAAAAAAAAAAAAAAAA=="
642 case "aws":
643 keyID = "AWSAAAAAAAAAAAAAAAAAAA=="
644 case "azure":
645 keyID = "AZUREAAAAAAAAAAAAAAAAA=="
646 case "gcp":
647 keyID = "GCPAAAAAAAAAAAAAAAAAAA=="
648 case "kmip":
649 keyID = "KMIPAAAAAAAAAAAAAAAAAA=="
650 default:
651 mt.Fatalf("unrecognized KMS provider %q", kms)
652 }
653
654 keyIDBytes, err := base64.StdEncoding.DecodeString(keyID)
655 assert.Nil(mt, err, "base64 DecodeString error: %v", err)
656 eo.SetKeyID(primitive.Binary{Subtype: 4, Data: keyIDBytes})
657 case "altname":
658 eo.SetKeyAltName(kms)
659 default:
660 mt.Fatalf("unrecognized identifier: %v", identifier)
661 }
662
663
664
665 var nestedIdx int32
666 nestedIdx, copied = bsoncore.AppendDocumentElementStart(copied, key)
667 docElems, _ := doc.Elements()
668 for _, de := range docElems {
669 deKey := de.Key()
670 deVal := de.Value()
671
672
673 if deKey != "value" {
674 copied = bsoncore.AppendValueElement(copied, deKey, rawValueToCoreValue(deVal))
675 continue
676 }
677
678 encrypted, err := cpt.clientEnc.Encrypt(context.Background(), deVal, eo)
679 if !doc.Lookup("allowed").Boolean() {
680
681
682 assert.NotNil(mt, err, "expected error encrypting value for key %v, got nil", key)
683 copied = bsoncore.AppendValueElement(copied, deKey, rawValueToCoreValue(deVal))
684 continue
685 }
686
687
688 assert.Nil(mt, err, "Encrypt error for key %v: %v", key, err)
689 copied = bsoncore.AppendBinaryElement(copied, deKey, encrypted.Subtype, encrypted.Data)
690 }
691 copied, _ = bsoncore.AppendDocumentEnd(copied, nestedIdx)
692 }
693 copied, _ = bsoncore.AppendDocumentEnd(copied, cidx)
694
695
696 _, err = cpt.cseColl.InsertOne(context.Background(), copied)
697 assert.Nil(mt, err, "InsertOne error for corpus document: %v", err)
698
699
700 decryptedDoc, err := cpt.cseColl.FindOne(context.Background(), bson.D{}).Raw()
701 assert.Nil(mt, err, "Find error with encrypted client: %v", err)
702 assert.Equal(mt, corpus, decryptedDoc, "expected document %v, got %v", corpus, decryptedDoc)
703
704
705 corpusEncrypted := readJSONFile(mt, "corpus-encrypted.json")
706 foundDoc, err := cpt.coll.FindOne(context.Background(), bson.D{}).Raw()
707 assert.Nil(mt, err, "Find error with unencrypted client: %v", err)
708
709 encryptedElems, _ := corpusEncrypted.Elements()
710 for _, encryptedElem := range encryptedElems {
711
712 encryptedDoc, ok := encryptedElem.Value().DocumentOK()
713 if !ok {
714 continue
715 }
716
717 allowed := encryptedDoc.Lookup("allowed").Boolean()
718 expectedKey := encryptedElem.Key()
719 expectedVal := encryptedDoc.Lookup("value")
720 foundVal := foundDoc.Lookup(expectedKey).Document().Lookup("value")
721
722
723
724 algo := encryptedDoc.Lookup("algo").StringValue()
725 switch algo {
726 case "det":
727 assert.True(mt, expectedVal.Equal(foundVal),
728 "expected value %v for key %v, got %v", expectedVal, expectedKey, foundVal)
729 case "rand":
730 if allowed {
731 assert.False(mt, expectedVal.Equal(foundVal),
732 "expected values for key %v to be different but were %v", expectedKey, expectedVal)
733 }
734 }
735
736
737 if allowed {
738 sub, data := expectedVal.Binary()
739 expectedDecrypted, err := cpt.clientEnc.Decrypt(context.Background(), primitive.Binary{Subtype: sub, Data: data})
740 assert.Nil(mt, err, "Decrypt error: %v", err)
741 sub, data = foundVal.Binary()
742 actualDecrypted, err := cpt.clientEnc.Decrypt(context.Background(), primitive.Binary{Subtype: sub, Data: data})
743 assert.Nil(mt, err, "Decrypt error: %v", err)
744
745 assert.True(mt, expectedDecrypted.Equal(actualDecrypted),
746 "expected decrypted value %v for key %v, got %v", expectedDecrypted, expectedKey, actualDecrypted)
747 continue
748 }
749
750
751 corpusVal := corpus.Lookup(expectedKey).Document().Lookup("value")
752 assert.True(mt, corpusVal.Equal(foundVal),
753 "expected value %v for key %v, got %v", corpusVal, expectedKey, foundVal)
754 }
755 })
756 }
757 })
758 mt.Run("7. custom endpoint", func(mt *mtest.T) {
759 validKmsProviders := map[string]map[string]interface{}{
760 "aws": {
761 "accessKeyId": awsAccessKeyID,
762 "secretAccessKey": awsSecretAccessKey,
763 },
764 "azure": {
765 "tenantId": azureTenantID,
766 "clientId": azureClientID,
767 "clientSecret": azureClientSecret,
768 "identityPlatformEndpoint": "login.microsoftonline.com:443",
769 },
770 "gcp": {
771 "email": gcpEmail,
772 "privateKey": gcpPrivateKey,
773 "endpoint": "oauth2.googleapis.com:443",
774 },
775 "kmip": {
776 "endpoint": "localhost:5698",
777 },
778 }
779
780 tlsConfig := make(map[string]*tls.Config)
781 if tlsCAFileKMIP != "" && tlsClientCertificateKeyFileKMIP != "" {
782 tlsOpts := map[string]interface{}{
783 "tlsCertificateKeyFile": tlsClientCertificateKeyFileKMIP,
784 "tlsCAFile": tlsCAFileKMIP,
785 }
786 kmipConfig, err := options.BuildTLSConfig(tlsOpts)
787 assert.Nil(mt, err, "BuildTLSConfig error: %v", err)
788 tlsConfig["kmip"] = kmipConfig
789 }
790
791 validClientEncryptionOptions := options.ClientEncryption().
792 SetKmsProviders(validKmsProviders).
793 SetKeyVaultNamespace(kvNamespace).
794 SetTLSConfig(tlsConfig)
795
796 invalidKmsProviders := map[string]map[string]interface{}{
797 "azure": {
798 "tenantId": azureTenantID,
799 "clientId": azureClientID,
800 "clientSecret": azureClientSecret,
801 "identityPlatformEndpoint": "doesnotexist.invalid:443",
802 },
803 "gcp": {
804 "email": gcpEmail,
805 "privateKey": gcpPrivateKey,
806 "endpoint": "doesnotexist.invalid:443",
807 },
808 "kmip": {
809 "endpoint": "doesnotexist.local:5698",
810 },
811 }
812
813 invalidClientEncryptionOptions := options.ClientEncryption().
814 SetKmsProviders(invalidKmsProviders).
815 SetKeyVaultNamespace(kvNamespace).
816 SetTLSConfig(tlsConfig)
817
818 awsSuccessWithoutEndpoint := map[string]interface{}{
819 "region": "us-east-1",
820 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
821 }
822 awsSuccessWithEndpoint := map[string]interface{}{
823 "region": "us-east-1",
824 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
825 "endpoint": "kms.us-east-1.amazonaws.com",
826 }
827 awsSuccessWithHTTPSEndpoint := map[string]interface{}{
828 "region": "us-east-1",
829 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
830 "endpoint": "kms.us-east-1.amazonaws.com:443",
831 }
832 awsFailureConnectionError := map[string]interface{}{
833 "region": "us-east-1",
834 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
835 "endpoint": "kms.us-east-1.amazonaws.com:12345",
836 }
837 awsFailureInvalidEndpoint := map[string]interface{}{
838 "region": "us-east-1",
839 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
840 "endpoint": "kms.us-east-2.amazonaws.com",
841 }
842 awsFailureParseError := map[string]interface{}{
843 "region": "us-east-1",
844 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
845 "endpoint": "doesnotexist.invalid",
846 }
847 azure := map[string]interface{}{
848 "keyVaultEndpoint": "key-vault-csfle.vault.azure.net",
849 "keyName": "key-name-csfle",
850 }
851 gcpSuccess := map[string]interface{}{
852 "projectId": "devprod-drivers",
853 "location": "global",
854 "keyRing": "key-ring-csfle",
855 "keyName": "key-name-csfle",
856 "endpoint": "cloudkms.googleapis.com:443",
857 }
858 gcpFailure := map[string]interface{}{
859 "projectId": "devprod-drivers",
860 "location": "global",
861 "keyRing": "key-ring-csfle",
862 "keyName": "key-name-csfle",
863 "endpoint": "doesnotexist.invalid:443",
864 }
865 kmipSuccessWithoutEndpoint := map[string]interface{}{
866 "keyId": "1",
867 }
868 kmipSuccessWithEndpoint := map[string]interface{}{
869 "keyId": "1",
870 "endpoint": "localhost:5698",
871 }
872 kmipFailureInvalidEndpoint := map[string]interface{}{
873 "keyId": "1",
874 "endpoint": "doesnotexist.local:5698",
875 }
876
877 const (
878 errConnectionRefused = "connection refused"
879 errInvalidKMSResponse = "Invalid KMS response"
880 errMongocryptError = "mongocrypt error"
881 errNoSuchHost = "no such host"
882 errServerMisbehaving = "server misbehaving"
883 errWindowsTLSConnectionRefused = "No connection could be made because the target machine actively refused it"
884 )
885
886 testCases := []struct {
887 name string
888 provider string
889 masterKey interface{}
890 errorSubstring []string
891 testInvalidClientEncryption bool
892 invalidClientEncryptionErrorSubstring []string
893 }{
894 {
895 name: "Case 1: aws success without endpoint",
896 provider: "aws",
897 masterKey: awsSuccessWithoutEndpoint,
898 errorSubstring: []string{},
899 testInvalidClientEncryption: false,
900 invalidClientEncryptionErrorSubstring: []string{},
901 },
902 {
903 name: "Case 2: aws success with endpoint",
904 provider: "aws",
905 masterKey: awsSuccessWithEndpoint,
906 errorSubstring: []string{},
907 testInvalidClientEncryption: false,
908 invalidClientEncryptionErrorSubstring: []string{},
909 },
910 {
911 name: "Case 3: aws success with https endpoint",
912 provider: "aws",
913 masterKey: awsSuccessWithHTTPSEndpoint,
914 errorSubstring: []string{},
915 testInvalidClientEncryption: false,
916 invalidClientEncryptionErrorSubstring: []string{},
917 },
918 {
919 name: "Case 4: aws failure with connection error",
920 provider: "aws",
921 masterKey: awsFailureConnectionError,
922 errorSubstring: []string{errConnectionRefused, errWindowsTLSConnectionRefused},
923 testInvalidClientEncryption: false,
924 invalidClientEncryptionErrorSubstring: []string{},
925 },
926 {
927 name: "Case 5: aws failure with wrong endpoint",
928 provider: "aws",
929 masterKey: awsFailureInvalidEndpoint,
930 errorSubstring: []string{errMongocryptError},
931 testInvalidClientEncryption: false,
932 invalidClientEncryptionErrorSubstring: []string{},
933 },
934 {
935 name: "Case 6: aws failure with parse error",
936 provider: "aws",
937 masterKey: awsFailureParseError,
938 errorSubstring: []string{errNoSuchHost, errServerMisbehaving},
939 testInvalidClientEncryption: false,
940 invalidClientEncryptionErrorSubstring: []string{},
941 },
942 {
943 name: "Case 7: azure success",
944 provider: "azure",
945 masterKey: azure,
946 errorSubstring: []string{},
947 testInvalidClientEncryption: true,
948 invalidClientEncryptionErrorSubstring: []string{errNoSuchHost, errServerMisbehaving},
949 },
950 {
951 name: "Case 8: gcp success",
952 provider: "gcp",
953 masterKey: gcpSuccess,
954 errorSubstring: []string{},
955 testInvalidClientEncryption: true,
956 invalidClientEncryptionErrorSubstring: []string{errNoSuchHost, errServerMisbehaving},
957 },
958 {
959 name: "Case 9: gcp failure",
960 provider: "gcp",
961 masterKey: gcpFailure,
962 errorSubstring: []string{errInvalidKMSResponse},
963 testInvalidClientEncryption: false,
964 invalidClientEncryptionErrorSubstring: []string{},
965 },
966 {
967 name: "Case 10: kmip success without endpoint",
968 provider: "kmip",
969 masterKey: kmipSuccessWithoutEndpoint,
970 errorSubstring: []string{},
971 testInvalidClientEncryption: true,
972 invalidClientEncryptionErrorSubstring: []string{errNoSuchHost, errServerMisbehaving},
973 },
974 {
975 name: "Case 11: kmip success with endpoint",
976 provider: "kmip",
977 masterKey: kmipSuccessWithEndpoint,
978 errorSubstring: []string{},
979 testInvalidClientEncryption: false,
980 invalidClientEncryptionErrorSubstring: []string{},
981 },
982 {
983 name: "Case 12: kmip failure with invalid endpoint",
984 provider: "kmip",
985 masterKey: kmipFailureInvalidEndpoint,
986 errorSubstring: []string{errNoSuchHost, errServerMisbehaving},
987 testInvalidClientEncryption: false,
988 invalidClientEncryptionErrorSubstring: []string{},
989 },
990 }
991 for _, tc := range testCases {
992 mt.Run(tc.name, func(mt *mtest.T) {
993 if strings.Contains(tc.name, "kmip") && "" == os.Getenv("KMS_MOCK_SERVERS_RUNNING") {
994 mt.Skipf("Skipping test as KMS_MOCK_SERVERS_RUNNING is not set")
995 }
996 cpt := setup(mt, nil, defaultKvClientOptions, validClientEncryptionOptions)
997 defer cpt.teardown(mt)
998
999 dkOpts := options.DataKey().SetMasterKey(tc.masterKey)
1000 createdKey, err := cpt.clientEnc.CreateDataKey(context.Background(), tc.provider, dkOpts)
1001 if len(tc.errorSubstring) > 0 {
1002 assert.NotNil(mt, err, "expected error, got nil")
1003
1004 assert.True(t, containsSubstring(tc.errorSubstring, err.Error()),
1005 "expected tc.errorSubstring=%v to contain %v, but it didn't", tc.errorSubstring, err.Error())
1006
1007 return
1008 }
1009 assert.Nil(mt, err, "CreateDataKey error: %v", err)
1010
1011 encOpts := options.Encrypt().SetKeyID(createdKey).SetAlgorithm(deterministicAlgorithm)
1012 testVal := bson.RawValue{
1013 Type: bson.TypeString,
1014 Value: bsoncore.AppendString(nil, "test"),
1015 }
1016 encrypted, err := cpt.clientEnc.Encrypt(context.Background(), testVal, encOpts)
1017 assert.Nil(mt, err, "Encrypt error: %v", err)
1018 decrypted, err := cpt.clientEnc.Decrypt(context.Background(), encrypted)
1019 assert.Nil(mt, err, "Decrypt error: %v", err)
1020 assert.Equal(mt, testVal, decrypted, "expected value %s, got %s", testVal, decrypted)
1021
1022 if !tc.testInvalidClientEncryption {
1023 return
1024 }
1025
1026 invalidClientEncryption, err := mongo.NewClientEncryption(cpt.kvClient, invalidClientEncryptionOptions)
1027 assert.Nil(mt, err, "error creating invalidClientEncryption object: %v", err)
1028 defer invalidClientEncryption.Close(context.Background())
1029
1030 invalidKeyOpts := options.DataKey().SetMasterKey(tc.masterKey)
1031 _, err = invalidClientEncryption.CreateDataKey(context.Background(), tc.provider, invalidKeyOpts)
1032 assert.NotNil(mt, err, "expected CreateDataKey error, got nil")
1033
1034 assert.True(t, containsSubstring(tc.invalidClientEncryptionErrorSubstring, err.Error()),
1035 "expected tc.invalidClientEncryptionErrorSubstring=%v to contain %v, but it didn't",
1036 tc.invalidClientEncryptionErrorSubstring, err.Error())
1037 })
1038 }
1039 })
1040 mt.RunOpts("8. bypass mongocryptd spawning", noClientOpts, func(mt *mtest.T) {
1041 mt.Parallel()
1042
1043 kmsProviders := map[string]map[string]interface{}{
1044 "local": {
1045 "key": localMasterKey,
1046 },
1047 }
1048 schemaMap := map[string]interface{}{
1049 "db.coll": readJSONFile(mt, "external-schema.json"),
1050 }
1051
1052
1053
1054
1055
1056 mongocryptdBypassSpawnTrue := map[string]interface{}{
1057 "mongocryptdBypassSpawn": true,
1058 "mongocryptdURI": "mongodb://localhost:27021/db?serverSelectionTimeoutMS=1000",
1059 "mongocryptdSpawnArgs": []string{"--pidfilepath=bypass-spawning-mongocryptd.pid", "--port=27021"},
1060 "__cryptSharedLibDisabledForTestOnly": true,
1061 }
1062 mongocryptdBypassSpawnFalse := map[string]interface{}{
1063 "mongocryptdBypassSpawn": false,
1064 "mongocryptdSpawnArgs": []string{"--pidfilepath=bypass-spawning-mongocryptd.pid", "--port=27021"},
1065 "__cryptSharedLibDisabledForTestOnly": true,
1066 }
1067 mongocryptdBypassSpawnNotSet := map[string]interface{}{
1068 "mongocryptdSpawnArgs": []string{"--pidfilepath=bypass-spawning-mongocryptd.pid", "--port=27021"},
1069 "__cryptSharedLibDisabledForTestOnly": true,
1070 }
1071
1072 testCases := []struct {
1073 name string
1074 mongocryptdOpts map[string]interface{}
1075 setBypassAutoEncryption bool
1076 bypassAutoEncryption bool
1077 bypassQueryAnalysis bool
1078 useSharedLib bool
1079 }{
1080 {
1081 name: "mongocryptdBypassSpawn only",
1082 mongocryptdOpts: mongocryptdBypassSpawnTrue,
1083 },
1084 {
1085 name: "bypassAutoEncryption only",
1086 mongocryptdOpts: mongocryptdBypassSpawnNotSet,
1087 setBypassAutoEncryption: true,
1088 bypassAutoEncryption: true,
1089 },
1090 {
1091 name: "mongocryptdBypassSpawn false, bypassAutoEncryption true",
1092 mongocryptdOpts: mongocryptdBypassSpawnFalse,
1093 setBypassAutoEncryption: true,
1094 bypassAutoEncryption: true,
1095 },
1096 {
1097 name: "mongocryptdBypassSpawn true, bypassAutoEncryption false",
1098 mongocryptdOpts: mongocryptdBypassSpawnTrue,
1099 setBypassAutoEncryption: true,
1100 bypassAutoEncryption: false,
1101 },
1102 {
1103 name: "bypassQueryAnalysis only",
1104 mongocryptdOpts: mongocryptdBypassSpawnNotSet,
1105 bypassQueryAnalysis: true,
1106 },
1107 {
1108 name: "use shared library",
1109 useSharedLib: true,
1110 mongocryptdOpts: map[string]interface{}{
1111 "mongocryptdURI": "mongodb://localhost:27021/db?serverSelectionTimeoutMS=1000",
1112 "mongocryptdSpawnArgs": []string{"--pidfilepath=bypass-spawning-mongocryptd.pid", "--port=27021"},
1113 "cryptSharedLibPath": os.Getenv("CRYPT_SHARED_LIB_PATH"),
1114 "cryptSharedRequired": true,
1115 },
1116 },
1117 }
1118 for _, tc := range testCases {
1119 mt.Run(tc.name, func(mt *mtest.T) {
1120 if tc.useSharedLib && os.Getenv("CRYPT_SHARED_LIB_PATH") == "" {
1121 mt.Skip("CRYPT_SHARED_LIB_PATH not set, skipping")
1122 return
1123 }
1124 aeo := options.AutoEncryption().
1125 SetKmsProviders(kmsProviders).
1126 SetKeyVaultNamespace(kvNamespace).
1127 SetSchemaMap(schemaMap).
1128 SetExtraOptions(tc.mongocryptdOpts)
1129 if tc.setBypassAutoEncryption {
1130 aeo.SetBypassAutoEncryption(tc.bypassAutoEncryption)
1131 }
1132 aeo.SetBypassQueryAnalysis(tc.bypassQueryAnalysis)
1133 cpt := setup(mt, aeo, nil, nil)
1134 defer cpt.teardown(mt)
1135
1136 _, err := cpt.cseColl.InsertOne(context.Background(), bson.D{{"unencrypted", "test"}})
1137
1138
1139 if !(tc.setBypassAutoEncryption && tc.bypassAutoEncryption) && !tc.bypassQueryAnalysis && !tc.useSharedLib {
1140 assert.NotNil(mt, err, "expected InsertOne error, got nil")
1141 mcryptErr, ok := err.(mongo.MongocryptdError)
1142 assert.True(mt, ok, "expected error type %T, got %v of type %T", mongo.MongocryptdError{}, err, err)
1143 assert.True(mt, strings.Contains(mcryptErr.Error(), "server selection error"),
1144 "expected mongocryptd server selection error, got %v", err)
1145 return
1146 }
1147
1148
1149
1150 assert.Nil(mt, err, "InsertOne error: %v", err)
1151
1152 mcryptOpts := options.Client().ApplyURI("mongodb://localhost:27021").
1153 SetServerSelectionTimeout(1 * time.Second)
1154 integtest.AddTestServerAPIVersion(mcryptOpts)
1155 mcryptClient, err := mongo.Connect(context.Background(), mcryptOpts)
1156 assert.Nil(mt, err, "mongocryptd Connect error: %v", err)
1157
1158 err = mcryptClient.Database("admin").RunCommand(context.Background(), bson.D{{handshake.LegacyHelloLowercase, 1}}).Err()
1159 assert.NotNil(mt, err, "expected mongocryptd legacy hello error, got nil")
1160 assert.True(mt, strings.Contains(err.Error(), "server selection error"),
1161 "expected mongocryptd server selection error, got %v", err)
1162 })
1163 }
1164 })
1165 changeStreamOpts := mtest.NewOptions().
1166 CreateClient(false).
1167 Topologies(mtest.ReplicaSet)
1168 mt.RunOpts("change streams", changeStreamOpts, func(mt *mtest.T) {
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179 var testConfig struct {
1180 JSONSchema bson.Raw `bson:"json_schema"`
1181 KeyVaultData []bson.Raw `bson:"key_vault_data"`
1182 EncryptedDocument bson.Raw `bson:"encrypted_document"`
1183 DecryptedDocument bson.Raw `bson:"decrytped_document"`
1184 }
1185 decodeJSONFile(mt, "change-streams-test.json", &testConfig)
1186
1187 schemaMap := map[string]interface{}{
1188 "db.coll": testConfig.JSONSchema,
1189 }
1190 kmsProviders := map[string]map[string]interface{}{
1191 "aws": {
1192 "accessKeyId": awsAccessKeyID,
1193 "secretAccessKey": awsSecretAccessKey,
1194 },
1195 }
1196
1197 testCases := []struct {
1198 name string
1199 streamType mongo.StreamType
1200 }{
1201 {"client", mongo.ClientStream},
1202 {"database", mongo.DatabaseStream},
1203 {"collection", mongo.CollectionStream},
1204 }
1205 mt.RunOpts("auto encryption errors", noClientOpts, func(mt *mtest.T) {
1206 mt.Parallel()
1207
1208 for _, tc := range testCases {
1209 mt.Run(tc.name, func(mt *mtest.T) {
1210 autoEncryptionOpts := options.AutoEncryption().
1211 SetKmsProviders(kmsProviders).
1212 SetKeyVaultNamespace(kvNamespace).
1213 SetSchemaMap(schemaMap).
1214 SetExtraOptions(getCryptSharedLibExtraOptions())
1215 cpt := setup(mt, autoEncryptionOpts, nil, nil)
1216 defer cpt.teardown(mt)
1217
1218 _, err := getWatcher(mt, tc.streamType, cpt).Watch(context.Background(), mongo.Pipeline{})
1219 assert.NotNil(mt, err, "expected Watch error: %v", err)
1220 })
1221 }
1222 })
1223 mt.RunOpts("events are automatically decrypted", noClientOpts, func(mt *mtest.T) {
1224 for _, tc := range testCases {
1225 mt.Run(tc.name, func(mt *mtest.T) {
1226 autoEncryptionOpts := options.AutoEncryption().
1227 SetKmsProviders(kmsProviders).
1228 SetKeyVaultNamespace(kvNamespace).
1229 SetSchemaMap(schemaMap).
1230 SetBypassAutoEncryption(true)
1231 cpt := setup(mt, autoEncryptionOpts, nil, nil)
1232 defer cpt.teardown(mt)
1233
1234
1235 insertDocuments(mt, cpt.keyVaultColl, testConfig.KeyVaultData)
1236
1237 stream, err := getWatcher(mt, tc.streamType, cpt).Watch(context.Background(), mongo.Pipeline{})
1238 assert.Nil(mt, err, "Watch error: %v", err)
1239 defer stream.Close(context.Background())
1240
1241
1242 insertDocuments(mt, cpt.coll, []bson.Raw{testConfig.EncryptedDocument})
1243 assert.True(mt, stream.Next(context.Background()), "expected Next to return true, got false")
1244 gotValue, err := stream.Current.LookupErr("fullDocument")
1245 assert.Nil(mt, err, "did not find fullDocument in stream.Current: %v", stream.Current)
1246 gotDocument := gotValue.Document()
1247 err = compareDocs(mt, testConfig.DecryptedDocument, gotDocument)
1248 assert.Nil(mt, err, "compareDocs error: %v", err)
1249 })
1250 }
1251 })
1252 })
1253 mt.RunOpts("9. deadlock tests", noClientOpts, func(mt *mtest.T) {
1254 testcases := []struct {
1255 description string
1256 maxPoolSize uint64
1257 bypassAutoEncryption bool
1258 keyVaultClientSet bool
1259 clientEncryptedTopologyOpeningExpected int
1260 clientEncryptedCommandStartedExpected []startedEvent
1261 clientKeyVaultCommandStartedExpected []startedEvent
1262 }{
1263
1264
1265 {
1266
1267
1268 "deadlock case 1", 1, false, false, 2,
1269 []startedEvent{{"listCollections", "db"}, {"find", "keyvault"}, {"insert", "db"}, {"find", "db"}},
1270 nil,
1271 },
1272 {
1273
1274
1275 "deadlock case 2", 1, false, true, 2,
1276 []startedEvent{{"listCollections", "db"}, {"insert", "db"}, {"find", "db"}},
1277 []startedEvent{{"find", "keyvault"}},
1278 },
1279 {
1280
1281
1282 "deadlock case 3", 1, true, false, 2,
1283 []startedEvent{{"find", "db"}, {"find", "keyvault"}},
1284 nil,
1285 },
1286 {
1287
1288
1289 "deadlock case 4", 1, true, true, 1,
1290 []startedEvent{{"find", "db"}},
1291 []startedEvent{{"find", "keyvault"}},
1292 },
1293 {
1294
1295
1296 "deadlock case 5", 0, false, false, 1,
1297 []startedEvent{{"listCollections", "db"}, {"listCollections", "keyvault"}, {"find", "keyvault"}, {"insert", "db"}, {"find", "db"}},
1298 nil,
1299 },
1300 {
1301
1302
1303 "deadlock case 6", 0, false, true, 1,
1304 []startedEvent{{"listCollections", "db"}, {"insert", "db"}, {"find", "db"}},
1305 []startedEvent{{"find", "keyvault"}},
1306 },
1307 {
1308
1309
1310 "deadlock case 7", 0, true, false, 1,
1311 []startedEvent{{"find", "db"}, {"find", "keyvault"}},
1312 nil,
1313 },
1314 {
1315
1316
1317 "deadlock case 8", 0, true, true, 1,
1318 []startedEvent{{"find", "db"}},
1319 []startedEvent{{"find", "keyvault"}},
1320 },
1321 }
1322
1323 for _, tc := range testcases {
1324 mt.Run(tc.description, func(mt *mtest.T) {
1325 var clientEncryptedEvents []startedEvent
1326 var clientEncryptedTopologyOpening int
1327
1328 d := newDeadlockTest(mt)
1329 defer d.disconnect(mt)
1330
1331 kmsProviders := map[string]map[string]interface{}{
1332 "local": {"key": localMasterKey},
1333 }
1334 aeOpts := options.AutoEncryption()
1335 aeOpts.SetKeyVaultNamespace("keyvault.datakeys").
1336 SetKmsProviders(kmsProviders).
1337 SetBypassAutoEncryption(tc.bypassAutoEncryption)
1338
1339
1340
1341
1342 if !tc.bypassAutoEncryption {
1343 aeOpts.SetExtraOptions(getCryptSharedLibExtraOptions())
1344 }
1345
1346 if tc.keyVaultClientSet {
1347 integtest.AddTestServerAPIVersion(d.clientKeyVaultOpts)
1348 aeOpts.SetKeyVaultClientOptions(d.clientKeyVaultOpts)
1349 }
1350
1351 ceOpts := options.Client().ApplyURI(mtest.ClusterURI()).
1352 SetMonitor(&event.CommandMonitor{
1353 Started: func(ctx context.Context, event *event.CommandStartedEvent) {
1354 clientEncryptedEvents = append(clientEncryptedEvents, startedEvent{event.CommandName, event.DatabaseName})
1355 },
1356 }).
1357 SetServerMonitor(&event.ServerMonitor{
1358 TopologyOpening: func(event *event.TopologyOpeningEvent) {
1359 clientEncryptedTopologyOpening++
1360 },
1361 }).
1362 SetMaxPoolSize(tc.maxPoolSize).
1363 SetAutoEncryptionOptions(aeOpts)
1364
1365 integtest.AddTestServerAPIVersion(ceOpts)
1366 clientEncrypted, err := mongo.Connect(context.Background(), ceOpts)
1367 assert.Nil(mt, err, "Connect error: %v", err)
1368 defer clientEncrypted.Disconnect(context.Background())
1369
1370 coll := clientEncrypted.Database("db").Collection("coll")
1371 if !tc.bypassAutoEncryption {
1372 _, err = coll.InsertOne(context.Background(), bson.M{"_id": 0, "encrypted": "string0"})
1373 } else {
1374 unencryptedColl := d.clientTest.Database("db").Collection("coll")
1375 _, err = unencryptedColl.InsertOne(context.Background(), bson.M{"_id": 0, "encrypted": d.ciphertext})
1376 }
1377 assert.Nil(mt, err, "InsertOne error: %v", err)
1378
1379 raw, err := coll.FindOne(context.Background(), bson.M{"_id": 0}).Raw()
1380 assert.Nil(mt, err, "FindOne error: %v", err)
1381
1382 expected := bsoncore.NewDocumentBuilder().
1383 AppendInt32("_id", 0).
1384 AppendString("encrypted", "string0").
1385 Build()
1386 assert.Equal(mt, bson.Raw(expected), raw, "returned value unequal, expected: %v, got: %v", expected, raw)
1387
1388 assert.Equal(mt, clientEncryptedEvents, tc.clientEncryptedCommandStartedExpected, "mismatched events for clientEncrypted. Expected %v, got %v", clientEncryptedEvents, tc.clientEncryptedCommandStartedExpected)
1389 assert.Equal(mt, d.clientKeyVaultEvents, tc.clientKeyVaultCommandStartedExpected, "mismatched events for clientKeyVault. Expected %v, got %v", d.clientKeyVaultEvents, tc.clientKeyVaultCommandStartedExpected)
1390 assert.Equal(mt, clientEncryptedTopologyOpening, tc.clientEncryptedTopologyOpeningExpected, "wrong number of TopologyOpening events. Expected %v, got %v", tc.clientEncryptedTopologyOpeningExpected, clientEncryptedTopologyOpening)
1391 })
1392 }
1393 })
1394
1395
1396
1397 mt.RunOpts("10. kms tls tests", noClientOpts, func(mt *mtest.T) {
1398 kmsTlsTestcase := os.Getenv("KMS_TLS_TESTCASE")
1399 if kmsTlsTestcase == "" {
1400 mt.Skipf("Skipping test as KMS_TLS_TESTCASE is not set")
1401 }
1402
1403 testcases := []struct {
1404 name string
1405 port int
1406 envValue string
1407 errMessage string
1408 }{
1409 {
1410 "invalid certificate",
1411 9000,
1412 "INVALID_CERT",
1413 "expired",
1414 },
1415 {
1416 "invalid hostname",
1417 9001,
1418 "INVALID_HOSTNAME",
1419 "SANs",
1420 },
1421 }
1422
1423 for _, tc := range testcases {
1424 mt.Run(tc.name, func(mt *mtest.T) {
1425
1426 if kmsTlsTestcase != tc.envValue {
1427 mt.Skipf("Skipping test as KMS_TLS_TESTCASE is set to %q, expected %v", kmsTlsTestcase, tc.envValue)
1428 }
1429
1430 ceo := options.ClientEncryption().
1431 SetKmsProviders(fullKmsProvidersMap).
1432 SetKeyVaultNamespace(kvNamespace)
1433 cpt := setup(mt, nil, nil, ceo)
1434 defer cpt.teardown(mt)
1435
1436 _, err := cpt.clientEnc.CreateDataKey(context.Background(), "aws", options.DataKey().SetMasterKey(
1437 bson.D{
1438 {"region", "us-east-1"},
1439 {"key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0"},
1440 {"endpoint", fmt.Sprintf("127.0.0.1:%d", tc.port)},
1441 },
1442 ))
1443 assert.NotNil(mt, err, "expected CreateDataKey error, got nil")
1444 assert.True(mt, strings.Contains(err.Error(), tc.errMessage),
1445 "expected CreateDataKey error to contain %v, got %v", tc.errMessage, err.Error())
1446 })
1447 }
1448 })
1449
1450
1451
1452 mt.RunOpts("11. kms tls options tests", noClientOpts, func(mt *mtest.T) {
1453 if os.Getenv("KMS_MOCK_SERVERS_RUNNING") == "" {
1454 mt.Skipf("Skipping test as KMS_MOCK_SERVERS_RUNNING is not set")
1455 }
1456 validKmsProviders := map[string]map[string]interface{}{
1457 "aws": {
1458 "accessKeyId": awsAccessKeyID,
1459 "secretAccessKey": awsSecretAccessKey,
1460 },
1461 "azure": {
1462 "tenantId": azureTenantID,
1463 "clientId": azureClientID,
1464 "clientSecret": azureClientSecret,
1465 "identityPlatformEndpoint": "127.0.0.1:9002",
1466 },
1467 "gcp": {
1468 "email": gcpEmail,
1469 "privateKey": gcpPrivateKey,
1470 "endpoint": "127.0.0.1:9002",
1471 },
1472 "kmip": {
1473 "endpoint": "127.0.0.1:5698",
1474 },
1475 }
1476
1477 expiredKmsProviders := map[string]map[string]interface{}{
1478 "aws": {
1479 "accessKeyId": awsAccessKeyID,
1480 "secretAccessKey": awsSecretAccessKey,
1481 },
1482 "azure": {
1483 "tenantId": azureTenantID,
1484 "clientId": azureClientID,
1485 "clientSecret": azureClientSecret,
1486 "identityPlatformEndpoint": "127.0.0.1:9000",
1487 },
1488 "gcp": {
1489 "email": gcpEmail,
1490 "privateKey": gcpPrivateKey,
1491 "endpoint": "127.0.0.1:9000",
1492 },
1493 "kmip": {
1494 "endpoint": "127.0.0.1:9000",
1495 },
1496 }
1497
1498 invalidKmsProviders := map[string]map[string]interface{}{
1499 "aws": {
1500 "accessKeyId": awsAccessKeyID,
1501 "secretAccessKey": awsSecretAccessKey,
1502 },
1503 "azure": {
1504 "tenantId": azureTenantID,
1505 "clientId": azureClientID,
1506 "clientSecret": azureClientSecret,
1507 "identityPlatformEndpoint": "127.0.0.1:9001",
1508 },
1509 "gcp": {
1510 "email": gcpEmail,
1511 "privateKey": gcpPrivateKey,
1512 "endpoint": "127.0.0.1:9001",
1513 },
1514 "kmip": {
1515 "endpoint": "127.0.0.1:9001",
1516 },
1517 }
1518
1519
1520 validClientEncryptionOptionsWithoutClientCert := options.ClientEncryption().
1521 SetKmsProviders(validKmsProviders).
1522 SetKeyVaultNamespace(kvNamespace)
1523
1524
1525 tlsConfig := make(map[string]*tls.Config)
1526 if tlsCAFileKMIP != "" && tlsClientCertificateKeyFileKMIP != "" {
1527 clientAndCATlsMap := map[string]interface{}{
1528 "tlsCertificateKeyFile": tlsClientCertificateKeyFileKMIP,
1529 "tlsCAFile": tlsCAFileKMIP,
1530 }
1531 certConfig, err := options.BuildTLSConfig(clientAndCATlsMap)
1532 assert.Nil(mt, err, "BuildTLSConfig error: %v", err)
1533 tlsConfig["aws"] = certConfig
1534 tlsConfig["azure"] = certConfig
1535 tlsConfig["gcp"] = certConfig
1536 tlsConfig["kmip"] = certConfig
1537 }
1538
1539
1540 validClientEncryptionOptionsWithTLS := options.ClientEncryption().
1541 SetKmsProviders(validKmsProviders).
1542 SetKeyVaultNamespace(kvNamespace).
1543 SetTLSConfig(tlsConfig)
1544
1545
1546 if tlsCAFileKMIP != "" {
1547 caTlsMap := map[string]interface{}{
1548 "tlsCAFile": tlsCAFileKMIP,
1549 }
1550 certConfig, err := options.BuildTLSConfig(caTlsMap)
1551 assert.Nil(mt, err, "BuildTLSConfig error: %v", err)
1552 tlsConfig["aws"] = certConfig
1553 tlsConfig["azure"] = certConfig
1554 tlsConfig["gcp"] = certConfig
1555 tlsConfig["kmip"] = certConfig
1556 }
1557
1558
1559 expiredClientEncryptionOptions := options.ClientEncryption().
1560 SetKmsProviders(expiredKmsProviders).
1561 SetKeyVaultNamespace(kvNamespace).
1562 SetTLSConfig(tlsConfig)
1563
1564
1565 invalidHostnameClientEncryptionOptions := options.ClientEncryption().
1566 SetKmsProviders(invalidKmsProviders).
1567 SetKeyVaultNamespace(kvNamespace).
1568 SetTLSConfig(tlsConfig)
1569
1570 awsMasterKeyNoClientCert := map[string]interface{}{
1571 "region": "us-east-1",
1572 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
1573 "endpoint": "127.0.0.1:9002",
1574 }
1575 awsMasterKeyWithTLS := map[string]interface{}{
1576 "region": "us-east-1",
1577 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
1578 "endpoint": "127.0.0.1:9002",
1579 }
1580 awsMasterKeyExpired := map[string]interface{}{
1581 "region": "us-east-1",
1582 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
1583 "endpoint": "127.0.0.1:9000",
1584 }
1585 awsMasterKeyInvalidHostname := map[string]interface{}{
1586 "region": "us-east-1",
1587 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
1588 "endpoint": "127.0.0.1:9001",
1589 }
1590 azureMasterKey := map[string]interface{}{
1591 "keyVaultEndpoint": "doesnotexist.local",
1592 "keyName": "foo",
1593 }
1594 gcpMasterKey := map[string]interface{}{
1595 "projectId": "foo",
1596 "location": "bar",
1597 "keyRing": "baz",
1598 "keyName": "foo",
1599 }
1600 kmipMasterKey := map[string]interface{}{}
1601
1602 testCases := []struct {
1603 name string
1604 masterKeyNoClientCert interface{}
1605 masterKeyWithTLS interface{}
1606 masterKeyExpired interface{}
1607 masterKeyInvalidHostname interface{}
1608 tlsError string
1609 expiredError string
1610 invalidHostnameError string
1611 }{
1612 {"aws", awsMasterKeyNoClientCert, awsMasterKeyWithTLS, awsMasterKeyExpired, awsMasterKeyInvalidHostname, "parse error", "certificate has expired", "cannot validate certificate"},
1613 {"azure", azureMasterKey, azureMasterKey, azureMasterKey, azureMasterKey, "HTTP status=404", "certificate has expired", "cannot validate certificate"},
1614 {"gcp", gcpMasterKey, gcpMasterKey, gcpMasterKey, gcpMasterKey, "HTTP status=404", "certificate has expired", "cannot validate certificate"},
1615 {"kmip", kmipMasterKey, kmipMasterKey, kmipMasterKey, kmipMasterKey, "", "certificate has expired", "cannot validate certificate"},
1616 }
1617
1618 for _, tc := range testCases {
1619 mt.Run(tc.name, func(mt *mtest.T) {
1620 if tc.name == "kmip" && "" == os.Getenv("KMS_MOCK_SERVERS_RUNNING") {
1621 mt.Skipf("Skipping test as KMS_MOCK_SERVERS_RUNNING is not set")
1622 }
1623
1624 cpt := setup(mt, nil, defaultKvClientOptions, validClientEncryptionOptionsWithoutClientCert)
1625 defer cpt.teardown(mt)
1626
1627 dkOpts := options.DataKey().SetMasterKey(tc.masterKeyNoClientCert)
1628 _, err := cpt.clientEnc.CreateDataKey(context.Background(), tc.name, dkOpts)
1629
1630 assert.NotNil(mt, err, "expected error, got nil")
1631 assert.True(mt, strings.Contains(err.Error(), "certificate signed by unknown authority"),
1632 "expected error '%s' to contain '%s'", err.Error(), "certificate signed by unknown authority")
1633
1634
1635 cpt = setup(mt, nil, defaultKvClientOptions, validClientEncryptionOptionsWithTLS)
1636
1637 dkOpts = options.DataKey().SetMasterKey(tc.masterKeyWithTLS)
1638 _, err = cpt.clientEnc.CreateDataKey(context.Background(), tc.name, dkOpts)
1639
1640 if tc.name == "kmip" {
1641 assert.Nil(mt, err, "expected no error, got err: %v", err)
1642 } else {
1643 assert.NotNil(mt, err, "expected error, got nil")
1644 assert.True(mt, strings.Contains(err.Error(), tc.tlsError),
1645 "expected error '%s' to contain '%s'", err.Error(), tc.tlsError)
1646 }
1647
1648
1649 cpt = setup(mt, nil, defaultKvClientOptions, expiredClientEncryptionOptions)
1650
1651 dkOpts = options.DataKey().SetMasterKey(tc.masterKeyExpired)
1652 _, err = cpt.clientEnc.CreateDataKey(context.Background(), tc.name, dkOpts)
1653 assert.NotNil(mt, err, "expected error, got nil")
1654 assert.True(mt, strings.Contains(err.Error(), tc.expiredError),
1655 "expected error '%s' to contain '%s'", err.Error(), tc.expiredError)
1656
1657
1658 cpt = setup(mt, nil, defaultKvClientOptions, invalidHostnameClientEncryptionOptions)
1659
1660 dkOpts = options.DataKey().SetMasterKey(tc.masterKeyInvalidHostname)
1661 _, err = cpt.clientEnc.CreateDataKey(context.Background(), tc.name, dkOpts)
1662 assert.NotNil(mt, err, "expected error, got nil")
1663 assert.True(mt, strings.Contains(err.Error(), tc.invalidHostnameError),
1664 "expected error '%s' to contain '%s'", err.Error(), tc.invalidHostnameError)
1665 })
1666 }
1667 })
1668 runOpts := mtest.NewOptions().MinServerVersion("7.0").Topologies(mtest.ReplicaSet, mtest.LoadBalanced, mtest.ShardedReplicaSet)
1669
1670
1671 mt.RunOpts("12. explicit encryption", runOpts, func(mt *mtest.T) {
1672
1673 encryptedFields := readJSONFile(mt, "encrypted-fields.json")
1674 key1Document := readJSONFile(mt, "key1-document.json")
1675 var key1ID primitive.Binary
1676 {
1677 subtype, data := key1Document.Lookup("_id").Binary()
1678 key1ID = primitive.Binary{Subtype: subtype, Data: data}
1679 }
1680
1681 testSetup := func() (*mongo.Client, *mongo.ClientEncryption) {
1682 mtest.DropEncryptedCollection(mt, mt.Client.Database("db").Collection("explicit_encryption"), encryptedFields)
1683 cco := options.CreateCollection().SetEncryptedFields(encryptedFields)
1684 err := mt.Client.Database("db").CreateCollection(context.Background(), "explicit_encryption", cco)
1685 assert.Nil(mt, err, "error on CreateCollection: %v", err)
1686 err = mt.Client.Database("keyvault").Collection("datakeys").Drop(context.Background())
1687 assert.Nil(mt, err, "error on Drop: %v", err)
1688 keyVaultClient, err := mongo.Connect(context.Background(), options.Client().ApplyURI(mtest.ClusterURI()))
1689 assert.Nil(mt, err, "error on Connect: %v", err)
1690 datakeysColl := keyVaultClient.Database("keyvault").Collection("datakeys", options.Collection().SetWriteConcern(mtest.MajorityWc))
1691 _, err = datakeysColl.InsertOne(context.Background(), key1Document)
1692 assert.Nil(mt, err, "error on InsertOne: %v", err)
1693
1694 ceo := options.ClientEncryption().
1695 SetKeyVaultNamespace("keyvault.datakeys").
1696 SetKmsProviders(fullKmsProvidersMap)
1697 clientEncryption, err := mongo.NewClientEncryption(keyVaultClient, ceo)
1698 assert.Nil(mt, err, "error on NewClientEncryption: %v", err)
1699
1700
1701 aeo := options.AutoEncryption().
1702 SetKeyVaultNamespace("keyvault.datakeys").
1703 SetKmsProviders(fullKmsProvidersMap).
1704 SetBypassQueryAnalysis(true)
1705 co := options.Client().SetAutoEncryptionOptions(aeo).ApplyURI(mtest.ClusterURI())
1706 encryptedClient, err := mongo.Connect(context.Background(), co)
1707 assert.Nil(mt, err, "error on Connect: %v", err)
1708 return encryptedClient, clientEncryption
1709 }
1710
1711
1712 mt.Run("case 1: can insert encrypted indexed and find", func(mt *mtest.T) {
1713 encryptedClient, clientEncryption := testSetup()
1714 defer clientEncryption.Close(context.Background())
1715 defer encryptedClient.Disconnect(context.Background())
1716
1717
1718 eo := options.Encrypt().SetAlgorithm("Indexed").SetKeyID(key1ID).SetContentionFactor(0)
1719 valueToEncrypt := "encrypted indexed value"
1720 rawVal := bson.RawValue{Type: bson.TypeString, Value: bsoncore.AppendString(nil, valueToEncrypt)}
1721 insertPayload, err := clientEncryption.Encrypt(context.Background(), rawVal, eo)
1722 assert.Nil(mt, err, "error in Encrypt: %v", err)
1723
1724 coll := encryptedClient.Database("db").Collection("explicit_encryption")
1725 _, err = coll.InsertOne(context.Background(), bson.D{{"_id", 1}, {"encryptedIndexed", insertPayload}})
1726 assert.Nil(mt, err, "Error in InsertOne: %v", err)
1727
1728 eo = options.Encrypt().SetAlgorithm("Indexed").SetKeyID(key1ID).SetQueryType(options.QueryTypeEquality).SetContentionFactor(0)
1729 findPayload, err := clientEncryption.Encrypt(context.Background(), rawVal, eo)
1730 assert.Nil(mt, err, "error in Encrypt: %v", err)
1731
1732 res := coll.FindOne(context.Background(), bson.D{{"encryptedIndexed", findPayload}})
1733 assert.Nil(mt, res.Err(), "Error in FindOne: %v", res.Err())
1734 got, err := res.Raw()
1735 assert.Nil(mt, err, "error in Raw: %v", err)
1736 gotValue, err := got.LookupErr("encryptedIndexed")
1737 assert.Nil(mt, err, "error in LookupErr: %v", err)
1738 assert.Equal(mt, gotValue.StringValue(), valueToEncrypt, "expected %q, got %q", valueToEncrypt, gotValue.StringValue())
1739 })
1740 mt.Run("case 2: can insert encrypted indexed and find with non-zero contention", func(mt *mtest.T) {
1741 encryptedClient, clientEncryption := testSetup()
1742 defer clientEncryption.Close(context.Background())
1743 defer encryptedClient.Disconnect(context.Background())
1744
1745 coll := encryptedClient.Database("db").Collection("explicit_encryption")
1746 valueToEncrypt := "encrypted indexed value"
1747 rawVal := bson.RawValue{Type: bson.TypeString, Value: bsoncore.AppendString(nil, valueToEncrypt)}
1748
1749 for i := 0; i < 10; i++ {
1750
1751 eo := options.Encrypt().SetAlgorithm("Indexed").SetKeyID(key1ID).SetContentionFactor(10)
1752 insertPayload, err := clientEncryption.Encrypt(context.Background(), rawVal, eo)
1753 assert.Nil(mt, err, "error in Encrypt: %v", err)
1754
1755 _, err = coll.InsertOne(context.Background(), bson.D{{"_id", i}, {"encryptedIndexed", insertPayload}})
1756 assert.Nil(mt, err, "Error in InsertOne: %v", err)
1757 }
1758
1759
1760 {
1761 eo := options.Encrypt().SetAlgorithm("Indexed").SetKeyID(key1ID).SetQueryType(options.QueryTypeEquality).SetContentionFactor(0)
1762 findPayload, err := clientEncryption.Encrypt(context.Background(), rawVal, eo)
1763 assert.Nil(mt, err, "error in Encrypt: %v", err)
1764
1765 cursor, err := coll.Find(context.Background(), bson.D{{"encryptedIndexed", findPayload}})
1766 assert.Nil(mt, err, "error in Find: %v", err)
1767 var got []bson.Raw
1768 err = cursor.All(context.Background(), &got)
1769 assert.Nil(mt, err, "error in All: %v", err)
1770 assert.True(mt, len(got) < 10, "expected len(got) < 10, got: %v", len(got))
1771 for _, doc := range got {
1772 gotValue, err := doc.LookupErr("encryptedIndexed")
1773 assert.Nil(mt, err, "error in LookupErr: %v", err)
1774 assert.Equal(mt, gotValue.StringValue(), valueToEncrypt, "expected %q, got %q", valueToEncrypt, gotValue.StringValue())
1775 }
1776 }
1777
1778
1779 {
1780 eo := options.Encrypt().SetAlgorithm("Indexed").SetKeyID(key1ID).SetQueryType(options.QueryTypeEquality).SetContentionFactor(10)
1781 findPayload2, err := clientEncryption.Encrypt(context.Background(), rawVal, eo)
1782 assert.Nil(mt, err, "error in Encrypt: %v", err)
1783
1784 cursor, err := coll.Find(context.Background(), bson.D{{"encryptedIndexed", findPayload2}})
1785 assert.Nil(mt, err, "error in Find: %v", err)
1786 var got []bson.Raw
1787 err = cursor.All(context.Background(), &got)
1788 assert.Nil(mt, err, "error in All: %v", err)
1789 assert.True(mt, len(got) == 10, "expected len(got) == 10, got: %v", len(got))
1790 for _, doc := range got {
1791 gotValue, err := doc.LookupErr("encryptedIndexed")
1792 assert.Nil(mt, err, "error in LookupErr: %v", err)
1793 assert.Equal(mt, gotValue.StringValue(), valueToEncrypt, "expected %q, got %q", valueToEncrypt, gotValue.StringValue())
1794 }
1795 }
1796 })
1797 mt.Run("case 3: can insert encrypted unindexed", func(mt *mtest.T) {
1798 encryptedClient, clientEncryption := testSetup()
1799 defer clientEncryption.Close(context.Background())
1800 defer encryptedClient.Disconnect(context.Background())
1801
1802
1803 eo := options.Encrypt().SetAlgorithm("Unindexed").SetKeyID(key1ID)
1804 valueToEncrypt := "encrypted unindexed value"
1805 rawVal := bson.RawValue{Type: bson.TypeString, Value: bsoncore.AppendString(nil, valueToEncrypt)}
1806 insertPayload, err := clientEncryption.Encrypt(context.Background(), rawVal, eo)
1807 assert.Nil(mt, err, "error in Encrypt: %v", err)
1808
1809 coll := encryptedClient.Database("db").Collection("explicit_encryption")
1810 _, err = coll.InsertOne(context.Background(), bson.D{{"_id", 1}, {"encryptedUnindexed", insertPayload}})
1811 assert.Nil(mt, err, "Error in InsertOne: %v", err)
1812
1813 res := coll.FindOne(context.Background(), bson.D{{"_id", 1}})
1814 assert.Nil(mt, res.Err(), "Error in FindOne: %v", res.Err())
1815 got, err := res.Raw()
1816 assert.Nil(mt, err, "error in Raw: %v", err)
1817 gotValue, err := got.LookupErr("encryptedUnindexed")
1818 assert.Nil(mt, err, "error in LookupErr: %v", err)
1819 assert.Equal(mt, gotValue.StringValue(), valueToEncrypt, "expected %q, got %q", valueToEncrypt, gotValue.StringValue())
1820 })
1821 mt.Run("case 4: can roundtrip encrypted indexed", func(mt *mtest.T) {
1822 encryptedClient, clientEncryption := testSetup()
1823 defer clientEncryption.Close(context.Background())
1824 defer encryptedClient.Disconnect(context.Background())
1825
1826
1827 eo := options.Encrypt().SetAlgorithm("Indexed").SetKeyID(key1ID).SetContentionFactor(0)
1828 valueToEncrypt := "encrypted indexed value"
1829 rawVal := bson.RawValue{Type: bson.TypeString, Value: bsoncore.AppendString(nil, valueToEncrypt)}
1830 payload, err := clientEncryption.Encrypt(context.Background(), rawVal, eo)
1831 assert.Nil(mt, err, "error in Encrypt: %v", err)
1832 gotValue, err := clientEncryption.Decrypt(context.Background(), payload)
1833 assert.Nil(mt, err, "error in Decrypt: %v", err)
1834 assert.Equal(mt, gotValue.StringValue(), valueToEncrypt, "expected %q, got %q", valueToEncrypt, gotValue.StringValue())
1835 })
1836 mt.Run("case 5: can roundtrip encrypted unindexed", func(mt *mtest.T) {
1837 encryptedClient, clientEncryption := testSetup()
1838 defer clientEncryption.Close(context.Background())
1839 defer encryptedClient.Disconnect(context.Background())
1840
1841
1842 eo := options.Encrypt().SetAlgorithm("Unindexed").SetKeyID(key1ID)
1843 valueToEncrypt := "encrypted unindexed value"
1844 rawVal := bson.RawValue{Type: bson.TypeString, Value: bsoncore.AppendString(nil, valueToEncrypt)}
1845 payload, err := clientEncryption.Encrypt(context.Background(), rawVal, eo)
1846 assert.Nil(mt, err, "error in Encrypt: %v", err)
1847 gotValue, err := clientEncryption.Decrypt(context.Background(), payload)
1848 assert.Nil(mt, err, "error in Decrypt: %v", err)
1849 assert.Equal(mt, gotValue.StringValue(), valueToEncrypt, "expected %q, got %q", valueToEncrypt, gotValue.StringValue())
1850 })
1851 })
1852
1853 runOpts = mtest.NewOptions().MinServerVersion("4.2").
1854 Topologies(mtest.ReplicaSet, mtest.LoadBalanced, mtest.ShardedReplicaSet)
1855 mt.RunOpts("13. Unique Index on keyAltNames", runOpts, func(mt *mtest.T) {
1856 const (
1857 dkCollection = "datakeys"
1858 idKey = "_id"
1859 kvDatabase = "keyvault"
1860 defKeyAltName = "def"
1861 abcKeyAltName = "abc"
1862 )
1863
1864 var cse *cseProseTest
1865
1866 var initialize = func() primitive.Binary {
1867
1868
1869 cse = setup(mt, nil, defaultKvClientOptions, options.ClientEncryption().
1870 SetKmsProviders(fullKmsProvidersMap).
1871 SetKeyVaultNamespace(kvNamespace))
1872
1873 err := cse.kvClient.Database(kvDatabase).Collection(dkCollection).Drop(context.Background())
1874 assert.Nil(mt, err, "error dropping %q namespace: %v", kvNamespace, err)
1875
1876
1877
1878 keyVaultIndex := mongo.IndexModel{
1879 Keys: bson.D{{"keyAltNames", 1}},
1880 Options: options.Index().
1881 SetUnique(true).
1882 SetName("keyAltNames_1").
1883 SetPartialFilterExpression(bson.D{
1884 {"keyAltNames", bson.D{
1885 {"$exists", true},
1886 }},
1887 }),
1888 }
1889
1890 wcMajority := writeconcern.New(writeconcern.WMajority(), writeconcern.WTimeout(1*time.Second))
1891 wcMajorityCollectionOpts := options.Collection().SetWriteConcern(wcMajority)
1892 wcmColl := cse.kvClient.Database(kvDatabase).Collection(dkCollection, wcMajorityCollectionOpts)
1893 _, err = wcmColl.Indexes().CreateOne(context.Background(), keyVaultIndex)
1894 assert.Nil(mt, err, "error creating keyAltNames index: %v", err)
1895
1896
1897 opts := options.DataKey().SetKeyAltNames([]string{defKeyAltName})
1898 defKeyID, err := cse.clientEnc.CreateDataKey(context.Background(), "local", opts)
1899 assert.Nil(mt, err, "error creating %q data key: %v", defKeyAltName, err)
1900 return defKeyID
1901 }
1902
1903 var validateAddKeyAltName = func(mt *mtest.T, cse *cseProseTest, res *mongo.SingleResult, expected ...string) {
1904 assert.Nil(mt, res.Err(), "error adding key alt name: %v", res.Err())
1905
1906 resbytes, err := res.Raw()
1907 assert.Nil(mt, err, "error decoding result bytes: %v", err)
1908
1909 idsubtype, iddata := bson.RawValue{Type: bsontype.EmbeddedDocument, Value: resbytes}.
1910 Document().Lookup("_id").Binary()
1911 filter := bsoncore.NewDocumentBuilder().AppendBinary("_id", idsubtype, iddata).Build()
1912
1913 ctx := context.Background()
1914 updatedData, err := cse.keyVaultColl.FindOne(ctx, filter).Raw()
1915 assert.Nil(mt, err, "error decoding result bytes: %v", err)
1916
1917 updated := bson.RawValue{Type: bsontype.EmbeddedDocument, Value: updatedData}
1918 updatedKeyAltNames, err := updated.Document().Lookup("keyAltNames").Array().Values()
1919 assert.Nil(mt, err, "error looking up raw keyAltNames: %v", err)
1920 assert.Equal(mt, len(updatedKeyAltNames), len(expected), "expected raw keyAltNames length to be 1")
1921
1922 for idx, keyAltName := range updatedKeyAltNames {
1923 str := keyAltName.StringValue()
1924 assert.Equal(mt, str, expected[idx], "expected keyAltName to be %q, got: %q", expected[idx], str)
1925 }
1926 }
1927
1928 mt.Run("case 1: createKey()", func(mt *mtest.T) {
1929 initialize()
1930
1931
1932
1933 opts := options.DataKey().SetKeyAltNames([]string{abcKeyAltName})
1934 _, err := cse.clientEnc.CreateDataKey(context.Background(), "local", opts)
1935 assert.Nil(mt, err, "error creating %q data key: %v", abcKeyAltName, err)
1936
1937
1938 opts = options.DataKey().SetKeyAltNames([]string{abcKeyAltName})
1939 _, err = cse.clientEnc.CreateDataKey(context.Background(), "local", opts)
1940 assert.NotNil(mt, err, "duplicate %q key did not propagate expected error", abcKeyAltName)
1941
1942 e110000 := "E11000 duplicate key"
1943 correctError := strings.Contains(err.Error(), e110000)
1944 assert.True(t, correctError, "expected error to contain %q, got: %v", e110000, err)
1945
1946
1947
1948 opts = options.DataKey().SetKeyAltNames([]string{defKeyAltName})
1949 _, err = cse.clientEnc.CreateDataKey(context.Background(), "local", opts)
1950 assert.NotNil(mt, err, "duplicate %q key did not propagate expected error", defKeyAltName)
1951
1952 e110000 = "E11000 duplicate key"
1953 correctError = strings.Contains(err.Error(), e110000)
1954 assert.True(t, correctError, "expected error to contain %q, got: %v", e110000, err)
1955 })
1956
1957 mt.Run("case 2: addKeyAltName()", func(t *mtest.T) {
1958 defKeyID := initialize()
1959
1960 var someNewKeyID primitive.Binary
1961
1962 var err error
1963 someNewKeyID, err = cse.clientEnc.CreateDataKey(context.Background(), "local")
1964 assert.Nil(mt, err, "error creating data key: %v", err)
1965
1966
1967
1968 res := cse.clientEnc.AddKeyAltName(context.Background(), someNewKeyID, abcKeyAltName)
1969 validateAddKeyAltName(mt, cse, res, abcKeyAltName)
1970
1971
1972
1973 res = cse.clientEnc.AddKeyAltName(context.Background(), someNewKeyID, abcKeyAltName)
1974 validateAddKeyAltName(mt, cse, res, abcKeyAltName)
1975
1976
1977
1978 res = cse.clientEnc.AddKeyAltName(context.Background(), someNewKeyID, defKeyAltName)
1979 assert.NotNil(mt, res.Err(), "duplicate %q key did not propagate expected error", defKeyAltName)
1980
1981 e110000 := "E11000 duplicate key"
1982 correctError := strings.Contains(res.Err().Error(), e110000)
1983 assert.True(t, correctError, "expected error to contain %q, got: %v", e110000, res.Err())
1984
1985
1986
1987 res = cse.clientEnc.AddKeyAltName(context.Background(), defKeyID, defKeyAltName)
1988 validateAddKeyAltName(mt, cse, res, defKeyAltName)
1989 })
1990
1991 })
1992
1993 mt.RunOpts("16. Rewrap", runOpts, func(mt *mtest.T) {
1994 mt.Run("Case 1: Rewrap with separate ClientEncryption", func(mt *mtest.T) {
1995 dataKeyMap := map[string]bson.M{
1996 "aws": {
1997 "region": "us-east-1",
1998 "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
1999 },
2000 "azure": {
2001 "keyVaultEndpoint": "key-vault-csfle.vault.azure.net",
2002 "keyName": "key-name-csfle",
2003 },
2004 "gcp": {
2005 "projectId": "devprod-drivers",
2006 "location": "global",
2007 "keyRing": "key-ring-csfle",
2008 "keyName": "key-name-csfle",
2009 },
2010 "kmip": {},
2011 }
2012
2013 tlsConfig := make(map[string]*tls.Config)
2014 if tlsCAFileKMIP != "" && tlsClientCertificateKeyFileKMIP != "" {
2015 tlsOpts := map[string]interface{}{
2016 "tlsCertificateKeyFile": tlsClientCertificateKeyFileKMIP,
2017 "tlsCAFile": tlsCAFileKMIP,
2018 }
2019 kmipConfig, err := options.BuildTLSConfig(tlsOpts)
2020 assert.Nil(mt, err, "BuildTLSConfig error: %v", err)
2021 tlsConfig["kmip"] = kmipConfig
2022 }
2023
2024 kmsProviders := []string{"local", "aws", "gcp", "azure", "kmip"}
2025 for _, srcProvider := range kmsProviders {
2026 for _, dstProvider := range kmsProviders {
2027 mt.Run(fmt.Sprintf("%s to %s", srcProvider, dstProvider), func(mt *mtest.T) {
2028 var err error
2029
2030 {
2031 err = mt.Client.Database("keyvault").Collection("datakeys").Drop(context.Background())
2032 assert.Nil(mt, err, "error on Drop: %v", err)
2033 }
2034
2035
2036 var clientEncryption1 *mongo.ClientEncryption
2037 {
2038 var keyVaultClient *mongo.Client
2039 {
2040 co := options.Client().ApplyURI(mtest.ClusterURI())
2041 keyVaultClient, err = mongo.Connect(context.Background(), co)
2042 defer keyVaultClient.Disconnect(context.Background())
2043 integtest.AddTestServerAPIVersion(co)
2044 assert.Nil(mt, err, "error on Connect: %v", err)
2045 }
2046 ceOpts := options.ClientEncryption().
2047 SetKeyVaultNamespace("keyvault.datakeys").
2048 SetKmsProviders(fullKmsProvidersMap).
2049 SetTLSConfig(tlsConfig)
2050 clientEncryption1, err = mongo.NewClientEncryption(keyVaultClient, ceOpts)
2051 assert.Nil(mt, err, "error in NewClientEncryption: %v", err)
2052 defer clientEncryption1.Close(context.Background())
2053 }
2054
2055
2056 var keyID primitive.Binary
2057 {
2058 dkOpts := options.DataKey()
2059 if val, ok := dataKeyMap[srcProvider]; ok {
2060 dkOpts.SetMasterKey(val)
2061 }
2062 keyID, err = clientEncryption1.CreateDataKey(context.Background(), srcProvider, dkOpts)
2063 assert.Nil(mt, err, "error in CreateDataKey: %v", err)
2064 }
2065
2066
2067 var ciphertext primitive.Binary
2068 {
2069 t, value, err := bson.MarshalValue("test")
2070 assert.Nil(mt, err, "error in MarshalValue: %v", err)
2071 plaintext := bson.RawValue{Type: t, Value: value}
2072 eOpts := options.Encrypt().SetKeyID(keyID).SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")
2073 ciphertext, err = clientEncryption1.Encrypt(context.Background(), plaintext, eOpts)
2074 assert.Nil(mt, err, "error in Encrypt: %v", err)
2075 }
2076
2077
2078 var clientEncryption2 *mongo.ClientEncryption
2079 {
2080 var keyVaultClient *mongo.Client
2081 {
2082 co := options.Client().ApplyURI(mtest.ClusterURI())
2083 keyVaultClient, err = mongo.Connect(context.Background(), co)
2084 defer keyVaultClient.Disconnect(context.Background())
2085 integtest.AddTestServerAPIVersion(co)
2086 assert.Nil(mt, err, "error on Connect: %v", err)
2087 }
2088 ceOpts := options.ClientEncryption().
2089 SetKeyVaultNamespace("keyvault.datakeys").
2090 SetKmsProviders(fullKmsProvidersMap).
2091 SetTLSConfig(tlsConfig)
2092 clientEncryption2, err = mongo.NewClientEncryption(keyVaultClient, ceOpts)
2093 assert.Nil(mt, err, "error in NewClientEncryption: %v", err)
2094 defer clientEncryption2.Close(context.Background())
2095 }
2096
2097
2098 {
2099 rwOpts := options.RewrapManyDataKey().SetProvider(dstProvider)
2100 if val, ok := dataKeyMap[dstProvider]; ok {
2101 rwOpts.SetMasterKey(val)
2102 }
2103 res, err := clientEncryption2.RewrapManyDataKey(context.Background(), bson.D{}, rwOpts)
2104 assert.Nil(mt, err, "error in RewrapManyDataKey: %v", err)
2105 assert.Equal(mt, res.BulkWriteResult.ModifiedCount, int64(1), "expected ModifiedCount of 1, got %v", res.BulkWriteResult.ModifiedCount)
2106 }
2107
2108
2109 {
2110 plaintext, err := clientEncryption1.Decrypt(context.Background(), ciphertext)
2111 assert.Nil(mt, err, "error in Decrypt: %v", err)
2112 assert.Equal(mt, plaintext.StringValue(), "test", "expected plaintext 'test', got %q", plaintext.StringValue())
2113 }
2114
2115
2116 {
2117 plaintext, err := clientEncryption2.Decrypt(context.Background(), ciphertext)
2118 assert.Nil(mt, err, "error in Decrypt: %v", err)
2119 assert.Equal(mt, plaintext.StringValue(), "test", "expected plaintext 'test', got %q", plaintext.StringValue())
2120 }
2121 })
2122 }
2123 }
2124 })
2125
2126 mt.Run("Case 2: RewrapManyDataKeyOpts.provider is not optional", func(mt *mtest.T) {
2127 var err error
2128 var clientEncryption *mongo.ClientEncryption
2129 {
2130 var keyVaultClient *mongo.Client
2131 {
2132 co := options.Client().ApplyURI(mtest.ClusterURI())
2133 keyVaultClient, err = mongo.Connect(context.Background(), co)
2134 defer keyVaultClient.Disconnect(context.Background())
2135 integtest.AddTestServerAPIVersion(co)
2136 assert.Nil(mt, err, "error on Connect: %v", err)
2137 }
2138 ceOpts := options.ClientEncryption().
2139 SetKeyVaultNamespace("keyvault.datakeys").
2140 SetKmsProviders(fullKmsProvidersMap)
2141 clientEncryption, err = mongo.NewClientEncryption(keyVaultClient, ceOpts)
2142 assert.Nil(mt, err, "error in NewClientEncryption: %v", err)
2143 defer clientEncryption.Close(context.Background())
2144 }
2145
2146 _, err = clientEncryption.RewrapManyDataKey(context.Background(), bson.D{}, options.RewrapManyDataKey().SetMasterKey(bson.D{}))
2147 assert.ErrorContains(mt, err, "expected 'Provider' to be set to identify type of 'MasterKey'")
2148 })
2149 })
2150
2151 mt.RunOpts("18. Azure IMDS Credentials", noClientOpts, func(mt *mtest.T) {
2152 buf := make([]byte, 0, 256)
2153 kmsProvidersMap := map[string]map[string]interface{}{
2154 "azure": {},
2155 }
2156 p, err := bson.MarshalAppend(buf[:0], kmsProvidersMap)
2157 assert.Nil(mt, err, "error in MarshalAppendWithRegistry: %v", err)
2158
2159 getClient := func(header http.Header) *http.Client {
2160 lt := &localTransport{
2161 header: header,
2162 rt: http.DefaultTransport,
2163 }
2164 return &http.Client{
2165 Timeout: 30 * time.Second,
2166 Transport: lt,
2167 }
2168 }
2169
2170 mt.Run("Case 1: Success", func(mt *mtest.T) {
2171 opts := &mongocryptopts.MongoCryptOptions{
2172 KmsProviders: p,
2173 HTTPClient: getClient(nil),
2174 }
2175 crypt, err := mongocrypt.NewMongoCrypt(opts)
2176 assert.Nil(mt, err, "error in NewMongoCrypt: %v", err)
2177 doc, err := crypt.GetKmsProviders(context.Background())
2178 assert.Nil(mt, err, "error in GetKmsProviders: %v", err)
2179 val, err := doc.LookupErr("azure")
2180 assert.Nil(mt, err, "error in LookupErr: %v", err)
2181 assert.Equal(mt, `{"accessToken": "magic-cookie"}`, val.String(), "expected accessToken, got %s", val.String())
2182 })
2183 mt.Run("Case 2: Empty JSON", func(mt *mtest.T) {
2184 header := make(http.Header)
2185 header.Set("X-MongoDB-HTTP-TestParams", "case=empty-json")
2186 opts := &mongocryptopts.MongoCryptOptions{
2187 KmsProviders: p,
2188 HTTPClient: getClient(header),
2189 }
2190 crypt, err := mongocrypt.NewMongoCrypt(opts)
2191 assert.Nil(mt, err, "error in NewMongoCrypt: %v", err)
2192 _, err = crypt.GetKmsProviders(context.Background())
2193 assert.ErrorContains(mt, err, "got unexpected empty accessToken")
2194 })
2195 mt.Run("Case 3: Bad JSON", func(mt *mtest.T) {
2196 header := make(http.Header)
2197 header.Set("X-MongoDB-HTTP-TestParams", "case=bad-json")
2198 opts := &mongocryptopts.MongoCryptOptions{
2199 KmsProviders: p,
2200 HTTPClient: getClient(header),
2201 }
2202 crypt, err := mongocrypt.NewMongoCrypt(opts)
2203 assert.Nil(mt, err, "error in NewMongoCrypt: %v", err)
2204 _, err = crypt.GetKmsProviders(context.Background())
2205 assert.ErrorContains(mt, err, "error reading body JSON")
2206 })
2207 mt.Run("Case 4: HTTP 404", func(mt *mtest.T) {
2208 header := make(http.Header)
2209 header.Set("X-MongoDB-HTTP-TestParams", "case=404")
2210 opts := &mongocryptopts.MongoCryptOptions{
2211 KmsProviders: p,
2212 HTTPClient: getClient(header),
2213 }
2214 crypt, err := mongocrypt.NewMongoCrypt(opts)
2215 assert.Nil(mt, err, "error in NewMongoCrypt: %v", err)
2216 _, err = crypt.GetKmsProviders(context.Background())
2217 assert.ErrorContains(mt, err, "got StatusCode: 404")
2218 })
2219 mt.Run("Case 5: HTTP 500", func(mt *mtest.T) {
2220 header := make(http.Header)
2221 header.Set("X-MongoDB-HTTP-TestParams", "case=500")
2222 opts := &mongocryptopts.MongoCryptOptions{
2223 KmsProviders: p,
2224 HTTPClient: getClient(header),
2225 }
2226 crypt, err := mongocrypt.NewMongoCrypt(opts)
2227 assert.Nil(mt, err, "error in NewMongoCrypt: %v", err)
2228 _, err = crypt.GetKmsProviders(context.Background())
2229 assert.ErrorContains(mt, err, "got StatusCode: 500")
2230 })
2231 mt.Run("Case 6: Slow Response", func(mt *mtest.T) {
2232 header := make(http.Header)
2233 header.Set("X-MongoDB-HTTP-TestParams", "case=slow")
2234 opts := &mongocryptopts.MongoCryptOptions{
2235 KmsProviders: p,
2236 HTTPClient: getClient(header),
2237 }
2238 crypt, err := mongocrypt.NewMongoCrypt(opts)
2239 assert.Nil(mt, err, "error in NewMongoCrypt: %v", err)
2240 _, err = crypt.GetKmsProviders(context.Background())
2241
2242 possibleErrors := []string{
2243 "error reading response body: context deadline exceeded",
2244 "Client.Timeout or context cancellation while reading body",
2245 }
2246
2247 assert.True(t, containsSubstring(possibleErrors, err.Error()),
2248 "expected possibleErrors=%v to contain %v, but it didn't",
2249 possibleErrors, err.Error())
2250 })
2251 })
2252
2253 mt.RunOpts("20. Bypass creating mongocryptd client when shared library is loaded",
2254 noClientOpts, func(mt *mtest.T) {
2255 cryptSharedLibPath := os.Getenv("CRYPT_SHARED_LIB_PATH")
2256 if cryptSharedLibPath == "" {
2257 mt.Skip("CRYPT_SHARED_LIB_PATH not set, skipping")
2258 return
2259 }
2260
2261 kmsProviders := map[string]map[string]interface{}{
2262 "local": {
2263 "key": localMasterKey,
2264 },
2265 }
2266
2267
2268 listener := listenForConnections(t, func(c net.Conn) {
2269 mt.Fatalf("Unexpected connection created to mock mongocryptd goroutine")
2270 c.Close()
2271 })
2272 defer listener.Close()
2273
2274 uri := "mongodb://" + listener.Addr().String()
2275 mongocryptdSpawnArgs := map[string]interface{}{
2276 "mongocryptdURI": uri,
2277 "cryptSharedLibPath": cryptSharedLibPath,
2278 }
2279
2280 aeo := options.AutoEncryption().SetKmsProviders(kmsProviders).
2281 SetExtraOptions(mongocryptdSpawnArgs)
2282 cliOpts := options.Client().ApplyURI(mtest.ClusterURI()).SetAutoEncryptionOptions(aeo)
2283 integtest.AddTestServerAPIVersion(cliOpts)
2284 encClient, err := mongo.Connect(context.Background(), cliOpts)
2285 assert.Nil(mt, err, "Connect error: %v", err)
2286 defer func() {
2287 err = encClient.Disconnect(context.Background())
2288 assert.Nil(mt, err, "encrypted client Disconnect error: %v", err)
2289 }()
2290
2291
2292
2293 _, err = encClient.Database("db").Collection("coll").InsertOne(context.Background(), bson.D{{"unencrypted", "test"}})
2294 assert.Nil(mt, err, "InsertOne error: %v", err)
2295 })
2296
2297
2298 qeRunOpts := mtest.NewOptions().MinServerVersion("7.0").Topologies(mtest.ReplicaSet, mtest.Sharded, mtest.LoadBalanced, mtest.ShardedReplicaSet)
2299
2300
2301 mt.RunOpts("21. automatic data encryption keys", qeRunOpts, func(mt *mtest.T) {
2302 setup := func() (*mongo.Client, *mongo.ClientEncryption, error) {
2303 opts := options.Client().ApplyURI(mtest.ClusterURI())
2304 client, err := mongo.Connect(context.Background(), opts)
2305 if err != nil {
2306 return nil, nil, err
2307 }
2308 client.Database("keyvault").Collection("datakeys").Drop(context.Background())
2309 client.Database("db").Drop(context.Background())
2310 ceo := options.ClientEncryption().
2311 SetKmsProviders(fullKmsProvidersMap).
2312 SetKeyVaultNamespace(kvNamespace)
2313 clientEnc, err := mongo.NewClientEncryption(client, ceo)
2314 if err != nil {
2315 return nil, nil, err
2316 }
2317 return client, clientEnc, nil
2318 }
2319
2320 type KMSProviderTestcase struct {
2321 kmsProvider string
2322 masterKey *bson.D
2323 }
2324
2325 testcases := []KMSProviderTestcase{
2326 {
2327 kmsProvider: "local",
2328 masterKey: nil,
2329 },
2330 {
2331 kmsProvider: "aws",
2332 masterKey: &bson.D{
2333 {"region", "us-east-1"},
2334 {"key", "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0"},
2335 },
2336 },
2337 }
2338
2339 for _, tc := range testcases {
2340 mt.Run(tc.kmsProvider, func(mt *mtest.T) {
2341
2342 mt.Run("case 1: simple creation and validation", func(mt *mtest.T) {
2343 client, clientEnc, err := setup()
2344 assert.Nil(mt, err, "setup error: %v", err)
2345 defer func() {
2346 err := clientEnc.Close(context.Background())
2347 assert.Nil(mt, err, "error in Close")
2348 }()
2349
2350 var encryptedFields bson.Raw
2351 err = bson.UnmarshalExtJSON([]byte(`{
2352 "fields": [{
2353 "path": "ssn",
2354 "bsonType": "string",
2355 "keyId": null
2356 }]
2357 }`), true , &encryptedFields)
2358 assert.Nil(mt, err, "Unmarshal error: %v", err)
2359
2360 coll, _, err := clientEnc.CreateEncryptedCollection(
2361 context.Background(),
2362 client.Database("db"),
2363 "testing1", options.CreateCollection().SetEncryptedFields(encryptedFields),
2364 "local", nil,
2365 )
2366 assert.Nil(mt, err, "CreateCollection error: %v", err)
2367
2368 _, err = coll.InsertOne(context.Background(), bson.D{{"ssn", "123-45-6789"}})
2369 assert.ErrorContains(mt, err, "Document failed validation")
2370 })
2371 mt.Run("case 2: missing encryptedFields", func(mt *mtest.T) {
2372 client, clientEnc, err := setup()
2373 assert.Nil(mt, err, "setup error: %v", err)
2374 defer func() {
2375 err := clientEnc.Close(context.Background())
2376 assert.Nil(mt, err, "error in Close")
2377 }()
2378
2379 coll, _, err := clientEnc.CreateEncryptedCollection(
2380 context.Background(),
2381 client.Database("db"),
2382 "testing1", options.CreateCollection(),
2383 "local", nil,
2384 )
2385 assert.Nil(mt, coll, "expect nil collection")
2386 assert.EqualError(mt, err, "no EncryptedFields defined for the collection")
2387 })
2388 mt.Run("case 3: invalid keyId", func(mt *mtest.T) {
2389 client, clientEnc, err := setup()
2390 assert.Nil(mt, err, "setup error: %v", err)
2391 defer func() {
2392 err := clientEnc.Close(context.Background())
2393 assert.Nil(mt, err, "error in Close")
2394 }()
2395
2396 var encryptedFields bson.Raw
2397 err = bson.UnmarshalExtJSON([]byte(`{
2398 "fields": [{
2399 "path": "ssn",
2400 "bsonType": "string",
2401 "keyId": false
2402 }]
2403 }`), true , &encryptedFields)
2404 assert.Nil(mt, err, "Unmarshal error: %v", err)
2405
2406 _, _, err = clientEnc.CreateEncryptedCollection(
2407 context.Background(),
2408 client.Database("db"),
2409 "testing1", options.CreateCollection().SetEncryptedFields(encryptedFields),
2410 "local", nil,
2411 )
2412 assert.ErrorContains(mt, err, "BSON field 'create.encryptedFields.fields.keyId' is the wrong type 'bool', expected type 'binData'")
2413 })
2414 mt.Run("case 4: insert encrypted value", func(mt *mtest.T) {
2415 client, clientEnc, err := setup()
2416 assert.Nil(mt, err, "setup error: %v", err)
2417 defer func() {
2418 err := clientEnc.Close(context.Background())
2419 assert.Nil(mt, err, "error in Close")
2420 }()
2421
2422 var encryptedFields bson.Raw
2423 err = bson.UnmarshalExtJSON([]byte(`{
2424 "fields": [{
2425 "path": "ssn",
2426 "bsonType": "string",
2427 "keyId": null
2428 }]
2429 }`), true , &encryptedFields)
2430 assert.Nil(mt, err, "Unmarshal error: %v", err)
2431
2432 coll, ef, err := clientEnc.CreateEncryptedCollection(
2433 context.Background(),
2434 client.Database("db"),
2435 "testing1", options.CreateCollection().SetEncryptedFields(encryptedFields),
2436 "local", nil,
2437 )
2438 assert.Nil(mt, err, "CreateCollection error: %v", err)
2439
2440 keyid := ef["fields"].(bson.A)[0].(bson.M)["keyId"].(primitive.Binary)
2441 rawValueType, rawValueData, err := bson.MarshalValue("123-45-6789")
2442 assert.Nil(mt, err, "MarshalValue error: %v", err)
2443 rawValue := bson.RawValue{Type: rawValueType, Value: rawValueData}
2444 encryptionOpts := options.Encrypt().
2445 SetAlgorithm("Unindexed").
2446 SetKeyID(keyid)
2447 encryptedField, err := clientEnc.Encrypt(
2448 context.Background(),
2449 rawValue,
2450 encryptionOpts)
2451 assert.Nil(mt, err, "Encrypt error: %v", err)
2452
2453 _, err = coll.InsertOne(context.Background(), bson.D{{"ssn", encryptedField}})
2454 assert.Nil(mt, err, "InsertOne error: %v", err)
2455 })
2456 })
2457 }
2458 })
2459
2460
2461 qeRunOpts22 := qeRunOpts.MaxServerVersion("7.99.99")
2462 mt.RunOpts("22. range explicit encryption", qeRunOpts22, func(mt *mtest.T) {
2463 type testcase struct {
2464 typeStr string
2465 field string
2466 typeBson bsontype.Type
2467 rangeOpts options.RangeOptions
2468 zero bson.RawValue
2469 six bson.RawValue
2470 thirty bson.RawValue
2471 twoHundred bson.RawValue
2472 twoHundredOne bson.RawValue
2473 }
2474
2475 precision := int32(2)
2476
2477 d128_0, err := primitive.ParseDecimal128("0")
2478 assert.Nil(mt, err)
2479 d128_6, err := primitive.ParseDecimal128("6")
2480 assert.Nil(mt, err)
2481 d128_30, err := primitive.ParseDecimal128("30")
2482 assert.Nil(mt, err)
2483 d128_200, err := primitive.ParseDecimal128("200")
2484 assert.Nil(mt, err)
2485 d128_201, err := primitive.ParseDecimal128("201")
2486 assert.Nil(mt, err)
2487
2488 tests := []testcase{
2489 {
2490 typeStr: "DecimalNoPrecision",
2491 field: "encryptedDecimalNoPrecision",
2492 typeBson: bson.TypeDecimal128,
2493 rangeOpts: options.RangeOptions{
2494 Sparsity: 1,
2495 },
2496 zero: bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_0)},
2497 six: bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_6)},
2498 thirty: bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_30)},
2499 twoHundred: bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_200)},
2500 twoHundredOne: bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_201)},
2501 },
2502 {
2503 typeStr: "DecimalPrecision",
2504 field: "encryptedDecimalPrecision",
2505 typeBson: bson.TypeDecimal128,
2506 rangeOpts: options.RangeOptions{
2507 Min: &bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_0)},
2508 Max: &bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_200)},
2509 Sparsity: 1,
2510 Precision: &precision,
2511 },
2512 zero: bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_0)},
2513 six: bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_6)},
2514 thirty: bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_30)},
2515 twoHundred: bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_200)},
2516 twoHundredOne: bson.RawValue{Type: bson.TypeDecimal128, Value: bsoncore.AppendDecimal128(nil, d128_201)},
2517 },
2518 {
2519 typeStr: "DoubleNoPrecision",
2520 field: "encryptedDoubleNoPrecision",
2521 typeBson: bson.TypeDouble,
2522 rangeOpts: options.RangeOptions{
2523 Sparsity: 1,
2524 },
2525 zero: bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 0)},
2526 six: bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 6)},
2527 thirty: bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 30)},
2528 twoHundred: bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 200)},
2529 twoHundredOne: bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 201)},
2530 },
2531 {
2532 typeStr: "DoublePrecision",
2533 field: "encryptedDoublePrecision",
2534 typeBson: bson.TypeDouble,
2535 rangeOpts: options.RangeOptions{
2536 Min: &bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 0)},
2537 Max: &bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 200)},
2538 Sparsity: 1,
2539 Precision: &precision,
2540 },
2541 zero: bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 0)},
2542 six: bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 6)},
2543 thirty: bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 30)},
2544 twoHundred: bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 200)},
2545 twoHundredOne: bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 201)},
2546 },
2547 {
2548 typeStr: "Date",
2549 field: "encryptedDate",
2550 typeBson: bson.TypeDateTime,
2551 rangeOpts: options.RangeOptions{
2552 Min: &bson.RawValue{Type: bson.TypeDateTime, Value: bsoncore.AppendDateTime(nil, 0)},
2553 Max: &bson.RawValue{Type: bson.TypeDateTime, Value: bsoncore.AppendDateTime(nil, 200)},
2554 Sparsity: 1,
2555 },
2556 zero: bson.RawValue{Type: bson.TypeDateTime, Value: bsoncore.AppendDateTime(nil, 0)},
2557 six: bson.RawValue{Type: bson.TypeDateTime, Value: bsoncore.AppendDateTime(nil, 6)},
2558 thirty: bson.RawValue{Type: bson.TypeDateTime, Value: bsoncore.AppendDateTime(nil, 30)},
2559 twoHundred: bson.RawValue{Type: bson.TypeDateTime, Value: bsoncore.AppendDateTime(nil, 200)},
2560 twoHundredOne: bson.RawValue{Type: bson.TypeDateTime, Value: bsoncore.AppendDateTime(nil, 201)},
2561 },
2562 {
2563 typeStr: "Int",
2564 field: "encryptedInt",
2565 typeBson: bson.TypeInt32,
2566 rangeOpts: options.RangeOptions{
2567 Min: &bson.RawValue{Type: bson.TypeInt32, Value: bsoncore.AppendInt32(nil, 0)},
2568 Max: &bson.RawValue{Type: bson.TypeInt32, Value: bsoncore.AppendInt32(nil, 200)},
2569 Sparsity: 1,
2570 },
2571 zero: bson.RawValue{Type: bson.TypeInt32, Value: bsoncore.AppendInt32(nil, 0)},
2572 six: bson.RawValue{Type: bson.TypeInt32, Value: bsoncore.AppendInt32(nil, 6)},
2573 thirty: bson.RawValue{Type: bson.TypeInt32, Value: bsoncore.AppendInt32(nil, 30)},
2574 twoHundred: bson.RawValue{Type: bson.TypeInt32, Value: bsoncore.AppendInt32(nil, 200)},
2575 twoHundredOne: bson.RawValue{Type: bson.TypeInt32, Value: bsoncore.AppendInt32(nil, 201)},
2576 },
2577 {
2578 typeStr: "Long",
2579 field: "encryptedLong",
2580 typeBson: bson.TypeInt64,
2581 rangeOpts: options.RangeOptions{
2582 Min: &bson.RawValue{Type: bson.TypeInt64, Value: bsoncore.AppendInt64(nil, 0)},
2583 Max: &bson.RawValue{Type: bson.TypeInt64, Value: bsoncore.AppendInt64(nil, 200)},
2584 Sparsity: 1,
2585 },
2586 zero: bson.RawValue{Type: bson.TypeInt64, Value: bsoncore.AppendInt64(nil, 0)},
2587 six: bson.RawValue{Type: bson.TypeInt64, Value: bsoncore.AppendInt64(nil, 6)},
2588 thirty: bson.RawValue{Type: bson.TypeInt64, Value: bsoncore.AppendInt64(nil, 30)},
2589 twoHundred: bson.RawValue{Type: bson.TypeInt64, Value: bsoncore.AppendInt64(nil, 200)},
2590 twoHundredOne: bson.RawValue{Type: bson.TypeInt64, Value: bsoncore.AppendInt64(nil, 201)},
2591 },
2592 }
2593
2594 for _, test := range tests {
2595 mt.Run(test.typeStr, func(mt *mtest.T) {
2596 if test.typeStr == "DecimalNoPrecision" && mtest.ClusterTopologyKind() != mtest.ReplicaSet {
2597 mt.Skipf("Skipping DecimalNoPrecision tests on a non ReplicaSet topology. DecimalNoPrecision queries are expected to take a long time and may exceed the default mongos timeout")
2598 }
2599
2600
2601 encryptedFields := readJSONFile(mt, fmt.Sprintf("range-encryptedFields-%v.json", test.typeStr))
2602 key1Document := readJSONFile(mt, "key1-document.json")
2603 var key1ID primitive.Binary
2604 {
2605 subtype, data := key1Document.Lookup("_id").Binary()
2606 key1ID = primitive.Binary{Subtype: subtype, Data: data}
2607 }
2608
2609 testSetup := func() (*mongo.Client, *mongo.ClientEncryption) {
2610 mtest.DropEncryptedCollection(mt, mt.Client.Database("db").Collection("explicit_encryption"), encryptedFields)
2611 cco := options.CreateCollection().SetEncryptedFields(encryptedFields)
2612 err := mt.Client.Database("db").CreateCollection(context.Background(), "explicit_encryption", cco)
2613 assert.Nil(mt, err, "error on CreateCollection: %v", err)
2614 err = mt.Client.Database("keyvault").Collection("datakeys").Drop(context.Background())
2615 assert.Nil(mt, err, "error on Drop: %v", err)
2616 keyVaultClient, err := mongo.Connect(context.Background(), options.Client().ApplyURI(mtest.ClusterURI()))
2617 assert.Nil(mt, err, "error on Connect: %v", err)
2618 datakeysColl := keyVaultClient.Database("keyvault").Collection("datakeys", options.Collection().SetWriteConcern(mtest.MajorityWc))
2619 _, err = datakeysColl.InsertOne(context.Background(), key1Document)
2620 assert.Nil(mt, err, "error on InsertOne: %v", err)
2621
2622 ceo := options.ClientEncryption().
2623 SetKeyVaultNamespace("keyvault.datakeys").
2624 SetKmsProviders(fullKmsProvidersMap)
2625 clientEncryption, err := mongo.NewClientEncryption(keyVaultClient, ceo)
2626 assert.Nil(mt, err, "error on NewClientEncryption: %v", err)
2627
2628
2629 aeo := options.AutoEncryption().
2630 SetKeyVaultNamespace("keyvault.datakeys").
2631 SetKmsProviders(fullKmsProvidersMap).
2632 SetBypassQueryAnalysis(true)
2633 co := options.Client().SetAutoEncryptionOptions(aeo).ApplyURI(mtest.ClusterURI())
2634 encryptedClient, err := mongo.Connect(context.Background(), co)
2635 assert.Nil(mt, err, "error on Connect: %v", err)
2636
2637
2638 coll := encryptedClient.Database("db").Collection("explicit_encryption")
2639 eo := options.Encrypt().
2640 SetAlgorithm("RangePreview").
2641 SetKeyID(key1ID).
2642 SetContentionFactor(0).
2643 SetRangeOptions(test.rangeOpts)
2644
2645 insertPayloadZero, err := clientEncryption.Encrypt(context.Background(), test.zero, eo)
2646 assert.Nil(mt, err, "error in Encrypt: %v", err)
2647 _, err = coll.InsertOne(context.Background(), bson.D{{"_id", 0}, {test.field, insertPayloadZero}})
2648 assert.Nil(mt, err, "error in InsertOne: %v", err)
2649
2650 insertPayloadSix, err := clientEncryption.Encrypt(context.Background(), test.six, eo)
2651 assert.Nil(mt, err, "error in Encrypt: %v", err)
2652 _, err = coll.InsertOne(context.Background(), bson.D{{"_id", 1}, {test.field, insertPayloadSix}})
2653 assert.Nil(mt, err, "error in InsertOne: %v", err)
2654
2655 insertPayloadThirty, err := clientEncryption.Encrypt(context.Background(), test.thirty, eo)
2656 assert.Nil(mt, err, "error in Encrypt: %v", err)
2657 _, err = coll.InsertOne(context.Background(), bson.D{{"_id", 2}, {test.field, insertPayloadThirty}})
2658 assert.Nil(mt, err, "error in InsertOne: %v", err)
2659
2660 insertPayloadTwoHundred, err := clientEncryption.Encrypt(context.Background(), test.twoHundred, eo)
2661 assert.Nil(mt, err, "error in Encrypt: %v", err)
2662 _, err = coll.InsertOne(context.Background(), bson.D{{"_id", 3}, {test.field, insertPayloadTwoHundred}})
2663 assert.Nil(mt, err, "error in InsertOne: %v", err)
2664
2665 return encryptedClient, clientEncryption
2666 }
2667
2668
2669
2670
2671
2672 checkCursorResults := func(cursor *mongo.Cursor, field string, values ...bson.RawValue) {
2673 for i, v := range values {
2674 assert.True(mt, cursor.Next(context.Background()), "expected Next true, got false. Expected document %v with value: %v", i, v)
2675 got, err := cursor.Current.LookupErr(test.field)
2676 assert.Nil(mt, err, "%v not found in document %v: %v", test.field, i, cursor.Current)
2677 assert.Equal(mt, v, got, "expected %v, got %v in document %v", v, got, i)
2678 }
2679 assert.False(mt, cursor.Next(context.Background()), "expected Next false, got true with document: %v", cursor.Current)
2680 }
2681
2682 mt.Run("Case 1: can decrypt a payload", func(mt *mtest.T) {
2683 encryptedClient, clientEncryption := testSetup()
2684 defer clientEncryption.Close(context.Background())
2685 defer encryptedClient.Disconnect(context.Background())
2686 eo := options.Encrypt().
2687 SetAlgorithm("RangePreview").
2688 SetKeyID(key1ID).
2689 SetContentionFactor(0).
2690 SetRangeOptions(test.rangeOpts)
2691 insertPayloadSix, err := clientEncryption.Encrypt(context.Background(), test.six, eo)
2692 assert.Nil(mt, err, "error in Encrypt: %v", err)
2693 got, err := clientEncryption.Decrypt(context.Background(), insertPayloadSix)
2694 assert.Nil(mt, err, "error in Decrypt: %v", err)
2695 assert.Equal(mt, test.six, got, "expected %v, got %v", test.six, got)
2696 })
2697
2698 mt.Run("Case 2: can find encrypted range and return the maximum", func(mt *mtest.T) {
2699 encryptedClient, clientEncryption := testSetup()
2700 defer clientEncryption.Close(context.Background())
2701 defer encryptedClient.Disconnect(context.Background())
2702 eo := options.Encrypt().
2703 SetAlgorithm("RangePreview").
2704 SetKeyID(key1ID).
2705 SetContentionFactor(0).
2706 SetQueryType("rangePreview").
2707 SetRangeOptions(test.rangeOpts)
2708
2709 expr := bson.M{
2710 "$and": bson.A{
2711 bson.M{
2712 test.field: bson.M{
2713 "$gte": test.six,
2714 },
2715 },
2716 bson.M{
2717 test.field: bson.M{
2718 "$lte": test.twoHundred,
2719 },
2720 },
2721 },
2722 }
2723
2724
2725 var encryptedExpr bson.Raw
2726 {
2727 err := clientEncryption.EncryptExpression(context.Background(), expr, &encryptedExpr, eo)
2728 assert.Nil(mt, err, "error in EncryptExpression: %v", err)
2729 }
2730
2731 coll := encryptedClient.Database("db").Collection("explicit_encryption")
2732 opts := options.Find().SetSort(bson.D{{"_id", 1}})
2733 cursor, err := coll.Find(context.Background(), encryptedExpr, opts)
2734 assert.Nil(mt, err, "error in coll.Find: %v", err)
2735 defer cursor.Close(context.Background())
2736
2737 checkCursorResults(cursor, test.field, test.six, test.thirty, test.twoHundred)
2738 })
2739
2740 mt.Run("Case 3: can find encrypted range and return the minimum", func(mt *mtest.T) {
2741 encryptedClient, clientEncryption := testSetup()
2742 defer clientEncryption.Close(context.Background())
2743 defer encryptedClient.Disconnect(context.Background())
2744 eo := options.Encrypt().
2745 SetAlgorithm("RangePreview").
2746 SetKeyID(key1ID).
2747 SetContentionFactor(0).
2748 SetQueryType("rangePreview").
2749 SetRangeOptions(test.rangeOpts)
2750
2751 expr := bson.M{
2752 "$and": bson.A{
2753 bson.M{
2754 test.field: bson.M{
2755 "$gte": test.zero,
2756 },
2757 },
2758 bson.M{
2759 test.field: bson.M{
2760 "$lte": test.six,
2761 },
2762 },
2763 },
2764 }
2765
2766
2767 var encryptedExpr bson.Raw
2768 {
2769 err := clientEncryption.EncryptExpression(context.Background(), expr, &encryptedExpr, eo)
2770 assert.Nil(mt, err, "error in EncryptExpression: %v", err)
2771 }
2772
2773 coll := encryptedClient.Database("db").Collection("explicit_encryption")
2774 opts := options.Find().SetSort(bson.D{{"_id", 1}})
2775 cursor, err := coll.Find(context.Background(), encryptedExpr, opts)
2776 assert.Nil(mt, err, "error in coll.Find: %v", err)
2777 defer cursor.Close(context.Background())
2778
2779 checkCursorResults(cursor, test.field, test.zero, test.six)
2780 })
2781
2782 mt.Run("Case 4: can find encrypted range with an open range query", func(mt *mtest.T) {
2783 encryptedClient, clientEncryption := testSetup()
2784 defer clientEncryption.Close(context.Background())
2785 defer encryptedClient.Disconnect(context.Background())
2786 eo := options.Encrypt().
2787 SetAlgorithm("RangePreview").
2788 SetKeyID(key1ID).
2789 SetContentionFactor(0).
2790 SetQueryType("rangePreview").
2791 SetRangeOptions(test.rangeOpts)
2792
2793 expr := bson.M{
2794 "$and": bson.A{
2795 bson.M{
2796 test.field: bson.M{
2797 "$gt": test.thirty,
2798 },
2799 },
2800 },
2801 }
2802
2803
2804 var encryptedExpr bson.Raw
2805 {
2806 err := clientEncryption.EncryptExpression(context.Background(), expr, &encryptedExpr, eo)
2807 assert.Nil(mt, err, "error in EncryptExpression: %v", err)
2808 }
2809
2810 coll := encryptedClient.Database("db").Collection("explicit_encryption")
2811 opts := options.Find().SetSort(bson.D{{"_id", 1}})
2812 cursor, err := coll.Find(context.Background(), encryptedExpr, opts)
2813 assert.Nil(mt, err, "error in coll.Find: %v", err)
2814 defer cursor.Close(context.Background())
2815
2816 checkCursorResults(cursor, test.field, test.twoHundred)
2817 })
2818
2819 mt.Run("Case 5: can run an aggregation expression inside $expr", func(mt *mtest.T) {
2820 encryptedClient, clientEncryption := testSetup()
2821 defer clientEncryption.Close(context.Background())
2822 defer encryptedClient.Disconnect(context.Background())
2823 eo := options.Encrypt().
2824 SetAlgorithm("RangePreview").
2825 SetKeyID(key1ID).
2826 SetContentionFactor(0).
2827 SetQueryType("rangePreview").
2828 SetRangeOptions(test.rangeOpts)
2829
2830 expr := bson.M{
2831 "$and": bson.A{
2832 bson.M{
2833 "$lt": bson.A{
2834 fmt.Sprintf("$%v", test.field),
2835 test.thirty,
2836 },
2837 },
2838 },
2839 }
2840
2841
2842 var encryptedExpr bson.Raw
2843 {
2844 err := clientEncryption.EncryptExpression(context.Background(), expr, &encryptedExpr, eo)
2845 assert.Nil(mt, err, "error in EncryptExpression: %v", err)
2846 }
2847
2848 coll := encryptedClient.Database("db").Collection("explicit_encryption")
2849 opts := options.Find().SetSort(bson.D{{"_id", 1}})
2850 cursor, err := coll.Find(context.Background(), bson.M{"$expr": encryptedExpr}, opts)
2851 assert.Nil(mt, err, "error in coll.Find: %v", err)
2852 defer cursor.Close(context.Background())
2853
2854 checkCursorResults(cursor, test.field, test.zero, test.six)
2855 })
2856
2857 if test.field != "encryptedDoubleNoPrecision" && test.field != "encryptedDecimalNoPrecision" {
2858 mt.Run("Case 6: encrypting a document greater than the maximum errors", func(mt *mtest.T) {
2859 encryptedClient, clientEncryption := testSetup()
2860 defer clientEncryption.Close(context.Background())
2861 defer encryptedClient.Disconnect(context.Background())
2862 eo := options.Encrypt().
2863 SetAlgorithm("RangePreview").
2864 SetKeyID(key1ID).
2865 SetContentionFactor(0).
2866 SetRangeOptions(test.rangeOpts)
2867
2868 _, err := clientEncryption.Encrypt(context.Background(), test.twoHundredOne, eo)
2869 assert.NotNil(mt, err, "expected error, but got none")
2870 })
2871
2872 mt.Run("Case 7: encrypting a document of a different type errors", func(mt *mtest.T) {
2873 encryptedClient, clientEncryption := testSetup()
2874 defer clientEncryption.Close(context.Background())
2875 defer encryptedClient.Disconnect(context.Background())
2876 eo := options.Encrypt().
2877 SetAlgorithm("RangePreview").
2878 SetKeyID(key1ID).
2879 SetContentionFactor(0).
2880 SetRangeOptions(test.rangeOpts)
2881
2882 var val bson.RawValue
2883 if test.field == "encryptedInt" {
2884 val = bson.RawValue{Type: bson.TypeDouble, Value: bsoncore.AppendDouble(nil, 6)}
2885 } else {
2886 val = bson.RawValue{Type: bson.TypeInt32, Value: bsoncore.AppendInt32(nil, 6)}
2887 }
2888
2889 _, err := clientEncryption.Encrypt(context.Background(), val, eo)
2890 assert.NotNil(mt, err, "expected error, but got none")
2891 })
2892 }
2893
2894 if test.field != "encryptedDoubleNoPrecision" && test.field != "encryptedDoublePrecision" && test.field != "encryptedDecimalNoPrecision" && test.field != "encryptedDecimalPrecision" {
2895 mt.Run("Case 8: setting precision errors if the type is not a double", func(mt *mtest.T) {
2896 encryptedClient, clientEncryption := testSetup()
2897 defer clientEncryption.Close(context.Background())
2898 defer encryptedClient.Disconnect(context.Background())
2899
2900
2901 ro := test.rangeOpts
2902 ro.SetPrecision(2)
2903 eo := options.Encrypt().
2904 SetAlgorithm("RangePreview").
2905 SetKeyID(key1ID).
2906 SetContentionFactor(0).
2907 SetRangeOptions(ro)
2908
2909 _, err := clientEncryption.Encrypt(context.Background(), test.six, eo)
2910 assert.NotNil(mt, err, "expected error, but got none")
2911 })
2912 }
2913 })
2914 }
2915 })
2916 }
2917
2918 func getWatcher(mt *mtest.T, streamType mongo.StreamType, cpt *cseProseTest) watcher {
2919 mt.Helper()
2920
2921 switch streamType {
2922 case mongo.ClientStream:
2923 return cpt.cseClient
2924 case mongo.DatabaseStream:
2925 return cpt.cseColl.Database()
2926 case mongo.CollectionStream:
2927 return cpt.cseColl
2928 default:
2929 mt.Fatalf("unknown stream type %v", streamType)
2930 }
2931 return nil
2932 }
2933
2934 type cseProseTest struct {
2935 coll *mongo.Collection
2936 kvClient *mongo.Client
2937 keyVaultColl *mongo.Collection
2938 cseClient *mongo.Client
2939 cseColl *mongo.Collection
2940 clientEnc *mongo.ClientEncryption
2941 cseStarted []*event.CommandStartedEvent
2942 }
2943
2944 func setup(mt *mtest.T, aeo *options.AutoEncryptionOptions, kvClientOpts *options.ClientOptions,
2945 ceo *options.ClientEncryptionOptions) *cseProseTest {
2946 mt.Helper()
2947 var cpt cseProseTest
2948 var err error
2949 cpt.coll = mt.CreateCollection(mtest.Collection{
2950 Name: "coll",
2951 DB: "db",
2952 Opts: options.Collection().SetWriteConcern(mtest.MajorityWc),
2953 }, false)
2954 cpt.keyVaultColl = mt.CreateCollection(mtest.Collection{
2955 Name: "datakeys",
2956 DB: "keyvault",
2957 Opts: options.Collection().SetWriteConcern(mtest.MajorityWc),
2958 }, false)
2959
2960 if aeo != nil {
2961 cseMonitor := &event.CommandMonitor{
2962 Started: func(_ context.Context, evt *event.CommandStartedEvent) {
2963 cpt.cseStarted = append(cpt.cseStarted, evt)
2964 },
2965 }
2966 opts := options.Client().ApplyURI(mtest.ClusterURI()).SetWriteConcern(mtest.MajorityWc).
2967 SetReadPreference(mtest.PrimaryRp).SetAutoEncryptionOptions(aeo).SetMonitor(cseMonitor)
2968 integtest.AddTestServerAPIVersion(opts)
2969 cpt.cseClient, err = mongo.Connect(context.Background(), opts)
2970 assert.Nil(mt, err, "Connect error for encrypted client: %v", err)
2971 cpt.cseColl = cpt.cseClient.Database("db").Collection("coll")
2972 }
2973 if ceo != nil {
2974 cpt.kvClient, err = mongo.Connect(context.Background(), kvClientOpts)
2975 assert.Nil(mt, err, "Connect error for ClientEncryption key vault client: %v", err)
2976 cpt.clientEnc, err = mongo.NewClientEncryption(cpt.kvClient, ceo)
2977 assert.Nil(mt, err, "NewClientEncryption error: %v", err)
2978 }
2979 return &cpt
2980 }
2981
2982 func (cpt *cseProseTest) teardown(mt *mtest.T) {
2983 mt.Helper()
2984
2985 if cpt.cseClient != nil {
2986 _ = cpt.cseClient.Disconnect(context.Background())
2987 }
2988 if cpt.clientEnc != nil {
2989 _ = cpt.clientEnc.Close(context.Background())
2990 }
2991 }
2992
2993 func readJSONFile(mt *mtest.T, file string) bson.Raw {
2994 mt.Helper()
2995
2996 content, err := ioutil.ReadFile(filepath.Join(clientEncryptionProseDir, file))
2997 assert.Nil(mt, err, "ReadFile error for %v: %v", file, err)
2998
2999 var doc bson.Raw
3000 err = bson.UnmarshalExtJSON(content, true, &doc)
3001 assert.Nil(mt, err, "UnmarshalExtJSON error for file %v: %v", file, err)
3002 return doc
3003 }
3004
3005 func decodeJSONFile(mt *mtest.T, file string, val interface{}) bson.Raw {
3006 mt.Helper()
3007
3008 content, err := ioutil.ReadFile(filepath.Join(clientEncryptionProseDir, file))
3009 assert.Nil(mt, err, "ReadFile error for %v: %v", file, err)
3010
3011 var doc bson.Raw
3012 err = bson.UnmarshalExtJSON(content, true, val)
3013 assert.Nil(mt, err, "UnmarshalExtJSON error for file %v: %v", file, err)
3014 return doc
3015 }
3016
3017 func rawValueToCoreValue(rv bson.RawValue) bsoncore.Value {
3018 return bsoncore.Value{Type: rv.Type, Data: rv.Value}
3019 }
3020
3021 type deadlockTest struct {
3022 clientTest *mongo.Client
3023 clientKeyVaultOpts *options.ClientOptions
3024 clientKeyVaultEvents []startedEvent
3025 clientEncryption *mongo.ClientEncryption
3026 ciphertext primitive.Binary
3027 }
3028
3029 type startedEvent struct {
3030 Command string
3031 Database string
3032 }
3033
3034 func newDeadlockTest(mt *mtest.T) *deadlockTest {
3035 mt.Helper()
3036
3037 var d deadlockTest
3038 var err error
3039
3040 clientTestOpts := options.Client().ApplyURI(mtest.ClusterURI()).SetWriteConcern(mtest.MajorityWc)
3041 integtest.AddTestServerAPIVersion(clientTestOpts)
3042 if d.clientTest, err = mongo.Connect(context.Background(), clientTestOpts); err != nil {
3043 mt.Fatalf("Connect error: %v", err)
3044 }
3045
3046 clientKeyVaultMonitor := &event.CommandMonitor{
3047 Started: func(ctx context.Context, event *event.CommandStartedEvent) {
3048 startedEvent := startedEvent{event.CommandName, event.DatabaseName}
3049 d.clientKeyVaultEvents = append(d.clientKeyVaultEvents, startedEvent)
3050 },
3051 }
3052
3053 d.clientKeyVaultOpts = options.Client().ApplyURI(mtest.ClusterURI()).
3054 SetMaxPoolSize(1).SetMonitor(clientKeyVaultMonitor)
3055
3056 keyvaultColl := d.clientTest.Database("keyvault").Collection("datakeys")
3057 dataColl := d.clientTest.Database("db").Collection("coll")
3058 err = dataColl.Drop(context.Background())
3059 assert.Nil(mt, err, "Drop error for collection db.coll: %v", err)
3060
3061 err = keyvaultColl.Drop(context.Background())
3062 assert.Nil(mt, err, "Drop error for key vault collection: %v", err)
3063
3064 keyDoc := readJSONFile(mt, "external-key.json")
3065 _, err = keyvaultColl.InsertOne(context.Background(), keyDoc)
3066 assert.Nil(mt, err, "InsertOne error into key vault collection: %v", err)
3067
3068 schemaDoc := readJSONFile(mt, "external-schema.json")
3069 createOpts := options.CreateCollection().SetValidator(bson.M{"$jsonSchema": schemaDoc})
3070 err = d.clientTest.Database("db").CreateCollection(context.Background(), "coll", createOpts)
3071 assert.Nil(mt, err, "CreateCollection error: %v", err)
3072
3073 kmsProviders := map[string]map[string]interface{}{
3074 "local": {"key": localMasterKey},
3075 }
3076 ceOpts := options.ClientEncryption().SetKmsProviders(kmsProviders).SetKeyVaultNamespace("keyvault.datakeys")
3077 d.clientEncryption, err = mongo.NewClientEncryption(d.clientTest, ceOpts)
3078 assert.Nil(mt, err, "NewClientEncryption error: %v", err)
3079
3080 t, value, err := bson.MarshalValue("string0")
3081 assert.Nil(mt, err, "MarshalValue error: %v", err)
3082 in := bson.RawValue{Type: t, Value: value}
3083 eopts := options.Encrypt().SetAlgorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic").SetKeyAltName("local")
3084 d.ciphertext, err = d.clientEncryption.Encrypt(context.Background(), in, eopts)
3085 assert.Nil(mt, err, "Encrypt error: %v", err)
3086
3087 return &d
3088 }
3089
3090 func (d *deadlockTest) disconnect(mt *mtest.T) {
3091 mt.Helper()
3092 err := d.clientEncryption.Close(context.Background())
3093 assert.Nil(mt, err, "clientEncryption Close error: %v", err)
3094 d.clientTest.Disconnect(context.Background())
3095 assert.Nil(mt, err, "clientTest Disconnect error: %v", err)
3096 }
3097
3098
3099
3100
3101 func listenForConnections(t *testing.T, run func(net.Conn)) net.Listener {
3102 t.Helper()
3103
3104 l, err := net.Listen("tcp", "localhost:0")
3105 if err != nil {
3106 t.Errorf("Could not set up a listener: %v", err)
3107 t.FailNow()
3108 }
3109 go func() {
3110 for {
3111
3112 c, _ := l.Accept()
3113 if c == nil {
3114 break
3115 }
3116 go run(c)
3117 }
3118 }()
3119 return l
3120 }
3121
3122 type localTransport struct {
3123 rt http.RoundTripper
3124
3125 header http.Header
3126 }
3127
3128 func (t *localTransport) RoundTrip(req *http.Request) (*http.Response, error) {
3129 r := req.Clone(req.Context())
3130 r.URL.Host = "localhost:8080"
3131 for key, vals := range t.header {
3132 for _, val := range vals {
3133 r.Header.Add(key, val)
3134 }
3135 }
3136 return t.rt.RoundTrip(r)
3137 }
3138
View as plain text