Skip to content

Commit fe35cdc

Browse files
committed
Update client-side encryption spec tests
1 parent aaf600c commit fe35cdc

30 files changed

+10018
-9885
lines changed

driver-core/src/test/resources/client-side-encryption/README.rst

Lines changed: 140 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The spec tests format is an extension of `transactions spec tests <https://githu
2424

2525
- A ``key_vault_data`` of data that should be inserted in the key vault collection before each test.
2626

27-
- Introduction ``client_side_encryption_opts`` to `clientOptions`
27+
- Introduction ``autoEncryptOpts`` to `clientOptions`
2828

2929
- Addition of `$db` to command in `command_started_event`
3030

@@ -193,6 +193,15 @@ Prose Tests
193193

194194
Tests for the ClientEncryption type are not included as part of the YAML tests.
195195

196+
In the prose tests LOCAL_MASTERKEY refers to the following base64:
197+
198+
.. code:: javascript
199+
200+
Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk
201+
202+
Data key and double encryption
203+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
204+
196205
First, perform the setup.
197206

198207
#. Create a MongoClient without encryption enabled (referred to as ``client``).
@@ -213,12 +222,6 @@ First, perform the setup.
213222
"local": { "key": <base64 decoding of LOCAL_MASTERKEY> }
214223
}
215224
216-
Where LOCAL_MASTERKEY is the following base64:
217-
218-
.. code:: javascript
219-
220-
Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk
221-
222225
Configure both objects with ``keyVaultNamespace`` set to ``admin.datakeys``.
223226

224227
Configure the ``MongoClient`` with the following ``schema_map``:
@@ -293,16 +296,128 @@ Then, run the following final tests:
293296
- Expect an exception to be thrown, since this is an attempt to auto encrypt an already encrypted value.
294297

295298

299+
300+
External Key Vault Test
301+
~~~~~~~~~~~~~~~~~~~~~~~
302+
303+
Run the following tests twice, parameterized by a boolean ``withExternalKeyVault``.
304+
305+
#. Create a MongoClient without encryption enabled (referred to as ``client``).
306+
307+
#. Using ``client``, drop the collections ``admin.datakeys`` and ``db.coll``.
308+
Insert the document `external/external-key.json <../external/external-key.json>`_ into ``admin.datakeys``.
309+
310+
#. Create the following:
311+
312+
- A MongoClient configured with auto encryption (referred to as ``client_encrypted``)
313+
- A ``ClientEncryption`` object (referred to as ``client_encryption``)
314+
315+
Configure both objects with the ``local`` KMS providers as follows:
316+
317+
.. code:: javascript
318+
319+
{ "local": { "key": <base64 decoding of LOCAL_MASTERKEY> } }
320+
321+
Configure both objects with ``keyVaultNamespace`` set to ``admin.datakeys``.
322+
323+
Configure ``client_encrypted`` to use the schema `external/external-schema.json <../external/external-schema.json>`_ for ``db.coll`` by setting a schema map like: ``{ "db.coll": <contents of external-schema.json>}``
324+
325+
If ``withExternalKeyVault == true``, configure both objects with an external key vault client. The external client MUST connect to the same
326+
MongoDB cluster that is being tested against, except it MUST use the username ``fake-user`` and password ``fake-pwd``.
327+
328+
#. Use ``client_encrypted`` to insert the document ``{"encrypted": "test"}`` into ``db.coll``.
329+
If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed.
330+
331+
#. Use ``client_encryption`` to explicitly encrypt the string ``"test"`` with key ID ``LOCALAAAAAAAAAAAAAAAAA==`` and deterministic algorithm.
332+
If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed.
333+
334+
335+
BSON size limits and batch splitting
336+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
337+
338+
First, perform the setup.
339+
340+
#. Create a MongoClient without encryption enabled (referred to as ``client``).
341+
342+
#. Using ``client``, drop and create the collection ``db.coll`` configured with the included JSON schema `limits/limits-schema.json <../limits/limits-schema.json>`_.
343+
344+
#. Using ``client``, drop the collection ``admin.datakeys``. Insert the document `limits/limits-key.json <../limits/limits-key.json>`_
345+
346+
#. Create a MongoClient configured with auto encryption (referred to as ``client_encrypted``)
347+
348+
Configure with the ``local`` KMS provider as follows:
349+
350+
.. code:: javascript
351+
352+
{ "local": { "key": <base64 decoding of LOCAL_MASTERKEY> } }
353+
354+
Configure with the ``keyVaultNamespace`` set to ``admin.datakeys``.
355+
356+
Using ``client_encrypted`` perform the following operations:
357+
358+
#. Insert ``{ "_id": "no_encryption_under_2mib", "unencrypted": <the string "a" repeated (2097152 - 1000) times> }``. (Note 2097152 is 2^21 bytes, or 2 MiB).
359+
360+
Expect this to succeed.
361+
362+
#. Insert ``{ "_id": "no_encryption_over_2mib", "unencrypted": <the string "a" repeated 2097152 times> }``.
363+
364+
Expect this to throw an exception due to exceeding the reduced maximum BSON document size.
365+
366+
#. Insert the document `limits/limits-doc.json <../limits/limits-doc.json>`_ concatenated with ``{ "_id": "encryption_exceeds_2mib", "unencrypted": < the string "a" repeated (2097152 - 2000) times > }``
367+
Note: limits-doc.json is a 1005 byte BSON document that encrypts to a ~10,000 byte document.
368+
369+
Expect this to succeed since after encryption this still is below the normal maximum BSON document size.
370+
Note, before auto encryption this document is under the 2 MiB limit. After encryption it exceeds the 2 MiB limit, but does NOT exceed the 16 MiB limit.
371+
372+
#. Bulk insert the following:
373+
374+
- ``{ "_id": "no_encryption_under_2mib_1", "unencrypted": <the string "a" repeated (2097152 - 1000) times> }``
375+
376+
- ``{ "_id": "no_encryption_under_2mib_2", "unencrypted": <the string "a" repeated (2097152 - 1000) times> }``
377+
378+
Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). This may be verified using `command monitoring <https://github.com/mongodb/specifications/tree/master/source/command-monitoring/command-monitoring.rst>`_.
379+
380+
#. Bulk insert the following:
381+
382+
- The document `limits/limits-doc.json <../limits/limits-doc.json>`_ concatenated with ``{ "_id": "encryption_exceeds_2mib_1", "unencrypted": < the string "a" repeated (2097152 - 2000) times > }``
383+
384+
- The document `limits/limits-doc.json <../limits/limits-doc.json>`_ concatenated with ``{ "_id": "encryption_exceeds_2mib_2", "unencrypted": < the string "a" repeated (2097152 - 2000) times > }``
385+
386+
Expect the bulk write to succeed and split after first doc (i.e. two inserts occur).
387+
388+
Optionally, if it is possible to mock the maxWriteBatchSize (i.e. the maximum number of documents in a batch) test that setting maxWriteBatchSize=1 and inserting the two documents ``{ "_id": "a" }, { "_id": "b" }`` with ``client_encrypted`` splits the operation into two inserts.
389+
390+
391+
Views are prohibited
392+
~~~~~~~~~~~~~~~~~~~~
393+
394+
#. Create a MongoClient without encryption enabled (referred to as ``client``).
395+
396+
#. Using ``client``, drop and create a view named ``db.view`` with an empty pipeline. E.g. using the command ``{ "create": "view", "viewOn": "coll" }``.
397+
398+
#. Create a MongoClient configured with auto encryption (referred to as ``client_encrypted``)
399+
400+
Configure with the ``local`` KMS provider as follows:
401+
402+
.. code:: javascript
403+
404+
{ "local": { "key": <base64 decoding of LOCAL_MASTERKEY> } }
405+
406+
Configure with the ``keyVaultNamespace`` set to ``admin.datakeys``.
407+
408+
#. Using ``client_encrypted``, attempt to insert a document into ``db.view``. Expect an exception to be thrown containing the message: "cannot auto encrypt a view".
409+
410+
296411
Corpus Test
297412
===========
298413

299414
The corpus test exhaustively enumerates all ways to encrypt all BSON value types. Note, the test data includes BSON binary subtype 4 (or standard UUID), which MUST be decoded and encoded as subtype 4. Run the test as follows.
300415

301416
1. Create a MongoClient without encryption enabled (referred to as ``client``).
302417

303-
2. Using ``client``, drop and create the collection ``db.coll`` configured with the included JSON schema `corpus/corpus-schema.json <corpus/corpus-schema.json>`_.
418+
2. Using ``client``, drop and create the collection ``db.coll`` configured with the included JSON schema `corpus/corpus-schema.json <../corpus/corpus-schema.json>`_.
304419

305-
3. Using ``client``, drop the collection ``admin.datakeys``. Insert the documents `corpus/corpus-key-local.json <corpus/corpus-key-local.json>`_ and `corpus/corpus-key-aws.json <corpus/corpus-key-aws.json>`_.
420+
3. Using ``client``, drop the collection ``admin.datakeys``. Insert the documents `corpus/corpus-key-local.json <../corpus/corpus-key-local.json>`_ and `corpus/corpus-key-aws.json <../corpus/corpus-key-aws.json>`_.
306421

307422
4. Create the following:
308423

@@ -319,14 +434,14 @@ The corpus test exhaustively enumerates all ways to encrypt all BSON value types
319434
}
320435
321436
Where LOCAL_MASTERKEY is the following base64:
322-
437+
323438
.. code:: javascript
324439
325440
Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk
326441
327442
Configure both objects with ``keyVaultNamespace`` set to ``admin.datakeys``.
328443

329-
5. Load `corpus/corpus.json <corpus/corpus.json>`_ to a variable named ``corpus``. The corpus contains subdocuments with the following fields:
444+
5. Load `corpus/corpus.json <../corpus/corpus.json>`_ to a variable named ``corpus``. The corpus contains subdocuments with the following fields:
330445

331446
- ``kms`` is either ``aws`` or ``local``
332447
- ``type`` is a BSON type string `names coming from here <https://docs.mongodb.com/manual/reference/operator/query/type/>`_)
@@ -342,15 +457,18 @@ The corpus test exhaustively enumerates all ways to encrypt all BSON value types
342457
- If the field name is ``_id``, ``altname_aws`` and ``altname_local``, copy the field to ``corpus_copied``.
343458
- If ``method`` is ``auto``, copy the field to ``corpus_copied``.
344459
- If ``method`` is ``explicit``, use ``client_encryption`` to explicitly encrypt the value.
345-
460+
346461
- Encrypt with the algorithm described by ``algo``.
347462
- If ``identifier`` is ``id``
348-
- If ``kms`` is ``local`` set the key_id to the UUID with base64 value ``LOCALAAAAAAAAAAAAAAAAA==``.
349-
- If ``kms`` is ``aws`` set the key_id to the UUID with base64 value ``AWSAAAAAAAAAAAAAAAAAAA==``.
463+
464+
- If ``kms`` is ``local`` set the key_id to the UUID with base64 value ``LOCALAAAAAAAAAAAAAAAAA==``.
465+
- If ``kms`` is ``aws`` set the key_id to the UUID with base64 value ``AWSAAAAAAAAAAAAAAAAAAA==``.
466+
350467
- If ``identifier`` is ``altname``
351-
- If ``kms`` is ``local`` set the key_alt_name to "local".
352-
- If ``kms`` is ``aws`` set the key_alt_name to "aws".
353-
468+
469+
- If ``kms`` is ``local`` set the key_alt_name to "local".
470+
- If ``kms`` is ``aws`` set the key_alt_name to "aws".
471+
354472
If ``allowed`` is true, copy the field and encrypted value to ``corpus_copied``.
355473
If ``allowed`` is false. verify that an exception is thrown. Copy the unencrypted value to to ``corpus_copied``.
356474

@@ -359,16 +477,15 @@ The corpus test exhaustively enumerates all ways to encrypt all BSON value types
359477

360478
7. Using ``client_encrypted``, find the inserted document from ``db.coll`` to a variable named ``corpus_decrypted``. Since it should have been automatically decrypted, assert the document exactly matches ``corpus``.
361479

362-
8. Load `corpus/corpus_encrypted.json <corpus/corpus-encrypted.json>`_ to a variable named ``corpus_encrypted_expected``.
480+
8. Load `corpus/corpus_encrypted.json <../corpus/corpus-encrypted.json>`_ to a variable named ``corpus_encrypted_expected``.
363481
Using ``client`` find the inserted document from ``db.coll`` to a variable named ``corpus_encrypted_actual``.
364482

365483
Iterate over each field of ``corpus_encrypted_expected`` and check the following:
366484

367-
- If the ``algo`` is ``det``, that the value exactly matches all fields in ``corpus_encrypted_actual`` with the same ``kms``, ``type``, and ``algo``.
368-
- If the ``algo`` is ``rand`` and ``allowed`` is true, that the value does not match any fields in ``corpus_encrypted_actual`` with the same ``kms`` and ``type``.
369-
- If the ``method`` is ``auto`` or ``explicit``, decrypt the value with ``client_encryption`` and validate the value exactly matches the corresponding field of ``corpus``.
370-
- If the ``allowed`` is false, validate the value exactly matches the corresponding field of ``corpus``.
485+
- If the ``algo`` is ``det``, that the value equals the value of the corresponding field in ``corpus_encrypted_actual``.
486+
- If the ``algo`` is ``rand`` and ``allowed`` is true, that the value does not equal the value of the corresponding field in ``corpus_encrypted_actual``.
487+
- If ``allowed`` is true, decrypt the value with ``client_encryption``. Decrypt the value of the corresponding field of ``corpus_encrypted`` and validate that they are both equal.
488+
- If ``allowed`` is false, validate the value exactly equals the value of the corresponding field of ``corpus`` (neither was encrypted).
371489

372490
9. Repeat steps 1-8 with a local JSON schema. I.e. amend step 4 to configure the schema on ``client_encrypted`` and ``client_encryption`` with the ``schema_map`` option.
373491

374-

0 commit comments

Comments
 (0)