Skip to content

DRIVERS-2017 Add spec and tests for rewrapManyDataKey and custom keyMaterial #1213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 44 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
218b5de
Relocate existing CSE tests into legacy subdirectory
eramongodb Apr 27, 2022
ff53d99
Add test format wording for client side encryption
eramongodb May 10, 2022
e356960
Add ClientEncryption.rewrapManyDataKey() to Client Side Encryption spec
eramongodb Apr 20, 2022
ebf2b93
Add DataKeyOpts.keyMaterial to Client Side Encryption spec
eramongodb Apr 27, 2022
6c903fb
Add unified test files for ClientEncryption.createKey()
eramongodb Apr 29, 2022
ee88894
Fix kmsProvider fields to use $$placeholder operator per schema 1.8
eramongodb May 10, 2022
e56aaa1
Apply spelling suggestions given in PR review
eramongodb May 10, 2022
f78cd90
Remove unnecessary useMultipleMongoses field
eramongodb May 12, 2022
bba079e
Fix name of rewrapManyDataKey-decrypt_failure test
eramongodb May 12, 2022
619c3fc
Clarify reason for failure in rewrapManyDataKey-decrypt_failure test
eramongodb May 12, 2022
395ec4f
Add check for multi field in update commands
eramongodb May 12, 2022
219b43f
Fix test description for rewrapManyDataKey-provider-current
eramongodb May 12, 2022
57de590
Use current createDataKey() function name instead of to-be-proposed c…
eramongodb May 12, 2022
3e1eadd
Move new legacy CSE tests into legacy subdirectory
eramongodb May 12, 2022
fcd6049
Add prose test for custom key material
eramongodb May 16, 2022
ed9875e
Merge remote-tracking branch 'upstream/master' into createKey-and-rew…
eramongodb May 16, 2022
c511d69
Update last modified dates and patch version for spec files
eramongodb May 16, 2022
f02cca1
Add createKey function to spec for consistency with name of unified t…
eramongodb May 16, 2022
57e12a8
Bump CSE spec version to 1.6.0
eramongodb May 17, 2022
e129b71
Remove redundant in expected results
eramongodb May 17, 2022
f1f56d7
Use generic names for database and collection
eramongodb May 17, 2022
afd6a9e
Remove quotes around base64 values for consistency
eramongodb May 17, 2022
de47fb9
Add reference to CRUD spec in description of bulkWriteResult
eramongodb May 17, 2022
3ceb273
Add newline after heading for consistency
eramongodb May 17, 2022
dea9455
Include "alias" in description of createDataKey
eramongodb May 17, 2022
452a7ad
Add paragraph break to CSE tests introduction
eramongodb May 17, 2022
ffca46e
Fix specification of keyVaultClient option for ClientEncryption objec…
eramongodb May 17, 2022
93e43ea
Remove unnecessary initialData in invalid_length test
eramongodb May 17, 2022
f7269c2
Remove unused observeEvents
eramongodb May 17, 2022
938cf33
Remove unnecessary "id" field in result of createKey tests
eramongodb May 17, 2022
5239907
Merge rewrapManyDataKey tests under single kms_providers test file
eramongodb May 17, 2022
2acfefd
Fix formatting of expectResult
eramongodb May 17, 2022
55e25ff
Correctly assert command events do not occur
eramongodb May 17, 2022
e050356
Merge createKey tests under single kms_providers test file
eramongodb May 17, 2022
ee9ef8a
Rename provider-invalid to kms_providers-invalid for consistency
eramongodb May 17, 2022
55634ce
Number prose tests in CSE spec
eramongodb May 17, 2022
a6a32fd
Clarify prose test spec to use majority write concern
eramongodb May 17, 2022
1a7f16d
Convert exact expectEvents to filtered find and aggregate expectResul…
eramongodb May 17, 2022
3fae1e6
Merge kms_providers and filter tests into single test file
eramongodb May 17, 2022
4fb3c6a
Ensure documents are sorted by keyAltName
eramongodb May 17, 2022
e8d1ba2
Reduce duplication in createKey test using merge key
eramongodb May 18, 2022
fc51b10
Merge remote-tracking branch 'upstream/master' into createKey-and-rew…
eramongodb May 18, 2022
d432d63
Add line breaks between tests for readability
eramongodb May 18, 2022
bd4b6ad
Add note explaining purpose of sorting resulting documents in find co…
eramongodb May 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 99 additions & 19 deletions source/client-side-encryption/client-side-encryption.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Client Side Encryption
:Status: Accepted
:Type: Standards
:Minimum Server Version: 4.2
:Last Modified: 2022-05-11
:Version: 1.5.2
:Last Modified: 2022-05-18
:Version: 1.6.0

.. _lmc-c-api: https://github.com/mongodb/libmongocrypt/blob/master/src/mongocrypt.h.in

Expand Down Expand Up @@ -708,8 +708,15 @@ ClientEncryption

// Creates a new key document and inserts into the key vault collection.
// Returns the \_id of the created document as a UUID (BSON binary subtype 4).
createKey(kmsProvider: String, opts: Optional<DataKeyOpts>): Binary;

// An alias function equivalent to createKey.
createDataKey(kmsProvider: String, opts: Optional<DataKeyOpts>): Binary;

// Decrypts multiple data keys and (re-)encrypts them with a new masterKey, or with their current masterKey if a new one is not given.
// Returns a RewrapManyDataKeyResult.
rewrapManyDataKey(filter: Document, opts: Optional<RewrapManyDataKeyOpts>): RewrapManyDataKeyResult;

// Encrypts a BSONValue with a given key and algorithm.
// Returns an encrypted value (BSON binary of subtype 6). The underlying implementation may return an error for prohibited BSON values.
encrypt(value: BSONValue, opts: EncryptOpts): Binary;
Expand All @@ -733,10 +740,11 @@ The ClientEncryption encapsulates explicit operations on a key vault
collection that cannot be done directly on a MongoClient. Similar to
configuring auto encryption on a MongoClient, it is
constructed with a MongoClient (to a MongoDB cluster containing the key
vault collection), KMS provider configuration, keyVaultNamespace, and tlsOptions. It
provides an API for explicitly encrypting and decrypting values, and
creating data keys. It does not provide an API to query keys from the key
vault collection, as this can be done directly on the MongoClient.
vault collection), KMS provider configuration, keyVaultNamespace, and
tlsOptions. It provides an API for explicitly encrypting and decrypting values,
creating data keys, and rewrapping data keys. It does not provide an API to
query keys from the key vault collection, as this can be done directly on the
MongoClient.

See `Why do we have a separate top level type for ClientEncryption?`_ and `Why do we need to pass a client to create a ClientEncryption?`_.

Expand All @@ -748,6 +756,7 @@ DataKeyOpts
class DataKeyOpts {
masterKey: Optional<Document>
keyAltNames: Optional<Array[String]> // An alternative to \_id to reference a key.
keyMaterial: Optional<BinData>
}

masterKey
Expand Down Expand Up @@ -824,6 +833,43 @@ example shows creating and referring to a data key by alternate name:
opts = EncryptOpts(keyAltName="name1", algorithm="AEAD_AES_256_CBC_HMAC_SHA_512-Random")
clientencryption.encrypt("457-55-5462", opts)

keyMaterial
~~~~~~~~~~~

An optional BinData of 96 bytes to use as custom key material for the data key
being created. If ``keyMaterial`` is given, the custom key material is used for
encrypting and decrypting data. Otherwise, the key material for the new data key
is generated from a cryptographically secure random device.

RewrapManyDataKeyOpts
---------------------

.. code:: typescript

class RewrapManyDataKeyOpts {
provider: String
masterKey: Optional<Document>
}

The ``masterKey`` document MUST have the fields corresponding to the given
``provider`` as specified in `masterKey`_. ``masterKey`` MUST NOT be given if
it is not applicable for the given ``provider``.

RewrapManyDataKeyResult
-----------------------

.. code:: typescript

class RewrapManyDataKeyResult {
bulkWriteResult: BulkWriteResult;
}

``bulkWriteResult`` is the `result of the bulk write operation
<../crud/crud.rst##write-results>`_ used to update the key vault collection with
rewrapped data keys.

See `Why does rewrapManyDataKey return RewrapManyDataKeyResult instead of BulkWriteResult?`_.

EncryptOpts
-----------

Expand Down Expand Up @@ -984,7 +1030,8 @@ users to distinguish when a command fails due to auto encryption limitations.
All errors from the MongoClient interacting with the key vault
collection MUST be distinguished in some way (e.g. exception type) to
make it easier for users to distinguish when a command fails due to
behind-the-scenes operations required for encryption or decryption.
behind-the-scenes operations required for encryption, decryption, or key
management.

Drivers MUST apply timeouts to operations executed as part of client-side encryption per `Client Side Operations
Timeout: Client Side Encryption
Expand Down Expand Up @@ -1275,31 +1322,39 @@ selection error is propagated to the user.
ClientEncryption
================
The new ClientEncryption type interacts uses libmongocrypt to perform
encryption and decryption, and to implement
ClientEncryption.createDataKey(), ClientEncryption.encrypt(), and
ClientEncryption.decrypt(). See the `libmongocrypt API documentation <https://github.com/mongodb/libmongocrypt/blob/master/src/mongocrypt.h.in>`_ for more information.
ClientEncryption.createKey() and ClientEncryption.rewrapManyDataKey(). See the
`libmongocrypt API documentation <https://github.com/mongodb/libmongocrypt/blob/master/src/mongocrypt.h.in>`_
for more information.

The ClientEncryption contains a MongoClient connected to the MongoDB
cluster containing the key vault collection. It does not contain a
MongoClient to mongocryptd.

Note, aside from createDataKey(), there is no new API for querying,
updating, or removing data keys. Much of this can be done with existing
CRUD operations.
See `Why does ClientEncryption have key management functions when Drivers can use existing CRUD operations instead?`_.

Key Vault collection
====================
The key vault collection is the specially designated collection
containing encrypted data keys. There is no default collection (user
must specify). The key vault collection is used for automatic and
explicit encryption/decryption as well as
ClientEncryption.createDataKey().
explicit encryption/decryption as well as key management functions.

For ClientEncryption.createDataKey(), the new document MUST be inserted
into the key vault collection with write concern majority.
For key management functions that require updating key documents in the key
vault collection, the corresponding create, update, or delete operations MUST be
done with write concern majority.

For encrytion/decryption that requires keys from the key vault
collection, the find operation MUST be done with read concern majority.
For encryption/decryption and key management functions that require reading
key documents from the key vault collection, the find operation MUST be done
with read concern majority.

Some key management functions may require multiple commands to complete their
operation. Key management functions currently assume there is no concurrent
access of the key vault collection being operated on. Concurrent access to a
key vault collection being operated on may result in unexpected or undefined
behavior. Support for concurrent key management may be considered for future
work.

See `Support sessions in key management functions`_.

Auto encrypt and decrypt
========================
Expand Down Expand Up @@ -2075,6 +2130,21 @@ Here is an example:

A rejected alternative to adding ``bypassQueryAnalysis`` is to change the behavior of ``bypassAutoEncryption``. ``bypassQueryAnalysis`` is distinct from ``bypassAutoEncryption``. ``bypassAutoEncryption`` bypasses all of libmongocrypt for commands. Changing the behavior of ``bypassAutoEncryption`` could harm performance (e.g. by serializing as smaller documents).

Why does rewrapManyDataKey return RewrapManyDataKeyResult instead of BulkWriteResult?
-------------------------------------------------------------------------------------

``rewrapManyDataKey`` is risky as it performs both a find and an update on the
key vault collection. Using ``RewrapManyDataKeyResult`` allows new fields to be
added in the future and more easily deprecate the wrapped ``BulkWriteResult`` if
necessary.

Why is there both a createKey and a createDataKey function in ClientEncryption?
-------------------------------------------------------------------------------

``createDataKey`` existed before ``createKey``, but ``createKey`` was added for
parity with the mongosh interface. ``createDataKey`` remains for backwards
compatibility.

Future work
===========

Expand Down Expand Up @@ -2136,6 +2206,15 @@ command with maxMessageSizeBytes=24MB. If after marking we determine
that's too large, try again with maxMessageSizeBytes=12MB and so on. And
in the end libmongocrypt would create multiple OP_MSGs to send.

Support sessions in key management functions
--------------------------------------------

Key management functions currently assume there are no concurrent accesses of
the key vault collection being operated on. To support concurrent access of the
key vault collection, the key management functions may be overloaded to take an
explicit session parameter as described in the
`Drivers Sessions Specification <../sessions/driver-sessions.rst>`__.

Changelog
=========

Expand All @@ -2144,6 +2223,7 @@ Changelog
:align: left

Date, Description
22-05-18, Add createKey and rewrapManyDataKey
22-05-11, Update create state collections to use clustered collections. Drop data collection after state collection.
22-05-03, Add queryType, contentionFactor, and "Indexed" and "Unindexed" to algorithm.
22-04-29, Add bypassQueryAnalysis option
Expand Down
81 changes: 54 additions & 27 deletions source/client-side-encryption/tests/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ Introduction
============

This document describes the format of the driver spec tests included in the
JSON and YAML files included in this directory. The
``timeoutMS.yml``/``timeoutMS.json`` files in this directory contain tests
for the ``timeoutMS`` option and its application to the client-side
encryption feature. Drivers MUST only run these tests after implementing the
JSON and YAML files included in the ``legacy`` sub-directory. Tests in the
``unified`` directory are written using the `Unified Test Format
<../../unified-test-format/unified-test-format.rst>`_.

The ``timeoutMS.yml``/``timeoutMS.json`` files in this directory contain tests
for the ``timeoutMS`` option and its application to the client-side encryption
feature. Drivers MUST only run these tests after implementing the
`Client Side Operations Timeout
<../client-side-operations-timeout/client-side-operations-timeout.rst>`__
specification.
Expand Down Expand Up @@ -371,8 +374,33 @@ In the prose tests LOCAL_MASTERKEY refers to the following base64:

Perform all applicable operations on key vault collections (e.g. inserting an example data key, or running a find command) with readConcern/writeConcern "majority".

Data key and double encryption
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Custom Key Material Test
~~~~~~~~~~~~~~~~~~~~~~~~~~~

#. Create a ``MongoClient`` object (referred to as ``client``).

#. Using ``client``, drop the collection ``keyvault.datakeys``.

#. Create a ``ClientEncryption`` object (referred to as ``client_encryption``) with ``client`` set as the ``keyVaultClient``.

#. Using ``client_encryption``, create a data key with a ``local`` KMS provider and the following custom key material (given as base64):

.. code:: javascript

xPTAjBRG5JiPm+d3fj6XLi2q5DMXUS/f1f+SMAlhhwkhDRL0kr8r9GDLIGTAGlvC+HVjSIgdL+RKwZCvpXSyxTICWSXTUYsWYPyu3IoHbuBZdmw2faM3WhcRIgbMReU5

#. Find the resulting key document in ``keyvault.datakeys``, save a copy of the key document, then remove the key document from the collection.

#. Replace the ``_id`` field in the copied key document with a UUID with base64 value ``AAAAAAAAAAAAAAAAAAAAAA==`` (16 bytes all equal to ``0x00``) and insert the modified key document into ``keyvault.datakeys`` with majority write concern.

#. Using ``client_encryption``, encrypt the string ``"test"`` with the modified data key using the ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic`` algorithm and assert the resulting value is equal to the following (given as base64):

.. code:: javascript

AQAAAAAAAAAAAAAAAAAAAAACz0ZOLuuhEYi807ZXTdhbqhLaS2/t9wLifJnnNYwiw79d75QYIZ6M/aYC1h9nCzCjZ7pGUpAuNnkUhnIXM3PjrA==

2. Data Key and Double Encryption
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

First, perform the setup.

Expand Down Expand Up @@ -502,8 +530,8 @@ For each KMS provider (``aws``, ``azure``, ``gcp``, ``local``, and ``kmip``), re



External Key Vault Test
~~~~~~~~~~~~~~~~~~~~~~~
3. External Key Vault Test
~~~~~~~~~~~~~~~~~~~~~~~~~~

Run the following tests twice, parameterized by a boolean ``withExternalKeyVault``.

Expand Down Expand Up @@ -537,8 +565,8 @@ Run the following tests twice, parameterized by a boolean ``withExternalKeyVault
If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed.


BSON size limits and batch splitting
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4. BSON Size Limits and Batch Splitting
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

First, perform the setup.

Expand Down Expand Up @@ -597,8 +625,8 @@ Using ``client_encrypted`` perform the following operations:
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.


Views are prohibited
~~~~~~~~~~~~~~~~~~~~
5. Views Are Prohibited
~~~~~~~~~~~~~~~~~~~~~~~

#. Create a MongoClient without encryption enabled (referred to as ``client``).

Expand All @@ -617,8 +645,8 @@ Views are prohibited
#. 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".


Corpus Test
~~~~~~~~~~~
6. Corpus Test
~~~~~~~~~~~~~~

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.

Expand Down Expand Up @@ -714,8 +742,8 @@ The corpus test exhaustively enumerates all ways to encrypt all BSON value types

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

Custom Endpoint Test
~~~~~~~~~~~~~~~~~~~~
7. Custom Endpoint Test
~~~~~~~~~~~~~~~~~~~~~~~

Setup
`````
Expand Down Expand Up @@ -934,8 +962,8 @@ Test cases

Expect this to fail with a network exception indicating failure to resolve "doesnotexist.local".

Bypass spawning mongocryptd
~~~~~~~~~~~~~~~~~~~~~~~~~~~
8. Bypass Spawning mongocryptd
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. note::

Expand Down Expand Up @@ -1014,9 +1042,8 @@ Via bypassQueryAnalysis

Repeat the steps from the "Via bypassAutoEncryption" test, replacing "bypassAutoEncryption=true" with "bypassQueryAnalysis=true".


Deadlock tests
~~~~~~~~~~~~~~
9. Deadlock Tests
~~~~~~~~~~~~~~~~~

.. _Connection Monitoring and Pooling: /source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.rst

Expand Down Expand Up @@ -1189,8 +1216,8 @@ Drivers that do not support an unlimited maximum pool size MUST skip this test.
- a find on "keyvault".
- ExpectedNumberOfClients: 1

KMS TLS Tests
~~~~~~~~~~~~~
10. KMS TLS Tests
~~~~~~~~~~~~~~~~~

.. _ca.pem: https://github.com/mongodb-labs/drivers-evergreen-tools/blob/master/.evergreen/x509gen/ca.pem
.. _expired.pem: https://github.com/mongodb-labs/drivers-evergreen-tools/blob/master/.evergreen/x509gen/expired.pem
Expand Down Expand Up @@ -1263,8 +1290,8 @@ Invalid Hostname in KMS Certificate
is "cannot validate certificate for 127.0.0.1 because it doesn't contain any IP SANs". If the language of implementation has a single, generic
error message for all certificate validation errors, drivers may inspect other fields of the error to verify its meaning.

KMS TLS Options Tests
~~~~~~~~~~~~~~~~~~~~~
11. KMS TLS Options Tests
~~~~~~~~~~~~~~~~~~~~~~~~~

Setup
`````
Expand Down Expand Up @@ -1572,8 +1599,8 @@ the same masterKey.

Expect an error indicating TLS handshake failed due to an invalid hostname.

Explicit Encryption
~~~~~~~~~~~~~~~~~~~
12. Explicit Encryption
~~~~~~~~~~~~~~~~~~~~~~~

The Explicit Encryption tests require MongoDB server 6.0+. The tests must not run against a standalone.

Expand Down
Loading