Skip to content
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

DRIVERS-2017 Add remaining Key Management API functions to spec and tests #1229

Merged
merged 25 commits into from May 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
98954b0
Add key management API to CSE spec
eramongodb May 19, 2022
0735124
Add CSE prose test for keyAltNames unique index
eramongodb May 20, 2022
add206b
Rename createKey-kms_providers to createKey for consistency
eramongodb May 19, 2022
ffe9ea8
Merge keyMaterial tests into createKey
eramongodb May 20, 2022
814f6ac
Add tests for keyAltNames in createKey
eramongodb May 20, 2022
0caa19d
Add unified tests for key management API functions
eramongodb May 19, 2022
a27e9dd
Remove escape character in comments of code blocks
eramongodb May 24, 2022
f461f1c
Change UUID type to Binary and specify UUID subtype
eramongodb May 24, 2022
8fb72e4
Fix description of getKeyByAltName
eramongodb May 24, 2022
563b747
Capitalize MAY per spec conventions
eramongodb May 24, 2022
9104648
Add reference to createIndex documentation
eramongodb May 24, 2022
ee6619f
Specify writeConcern level in prose test spec
eramongodb May 24, 2022
eafa6b7
Include error code when asserting duplicate key errors
eramongodb May 24, 2022
4e709be
Change capitalization of BSONValue -> BsonValue for consistency
eramongodb May 24, 2022
44605c9
Remove match assertion for acknowledged field
eramongodb May 25, 2022
b9f2c5f
Change return type for functions returning zero-or-one documents to O…
eramongodb May 25, 2022
cc11f67
Add missing name field to createIndexes command
eramongodb May 25, 2022
42c7d52
Fix capitalization of keyAltNames in addKeyAlternateName
eramongodb May 25, 2022
1b62faa
Rename Alternate -> Alt in function names
eramongodb May 25, 2022
b244242
Add commandStartedEvents to ensure consistent commands across impleme…
eramongodb May 25, 2022
8561777
Fix RST heading punctuation length
eramongodb May 25, 2022
6b1e14b
Fix prose test number for Unique Index on keyAltNames
eramongodb May 26, 2022
2098052
Fix value of key field in example command
eramongodb May 26, 2022
b68292e
Further clarify permitted UUID-equivalent types
eramongodb May 26, 2022
6936f43
Avoid prescribing preference, just defer to existing spec
eramongodb May 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
77 changes: 58 additions & 19 deletions source/client-side-encryption/client-side-encryption.rst
Expand Up @@ -10,8 +10,8 @@ Client Side Encryption
:Status: Accepted
:Type: Standards
:Minimum Server Version: 4.2
:Last Modified: 2022-05-18
:Version: 1.6.0
:Last Modified: 2022-05-24
:Version: 1.7.0

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

Expand Down Expand Up @@ -302,6 +302,10 @@ Drivers MAY deviate the spelling of option names to conform to their
language's naming conventions and implement options in an idiomatic way
(e.g. keyword arguments, builder classes, etc.).

Drivers MAY use a native UUID type in place of a parameter or return type
specified as a BSON binary with subtype 0x04 as described in
`Handling of Native UUID Types <../uuid.rst>`.

MongoClient Changes
-------------------

Expand Down Expand Up @@ -707,7 +711,7 @@ ClientEncryption
ClientEncryption(opts: ClientEncryptionOpts);

// 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).
// Returns the _id of the created document as a UUID (BSON binary subtype 0x04).
createKey(kmsProvider: String, opts: Optional<DataKeyOpts>): Binary;

// An alias function equivalent to createKey.
Expand All @@ -717,12 +721,36 @@ ClientEncryption
// 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;
// Removes the key document with the given UUID (BSON binary subtype 0x04) from the key vault collection.
// Returns the result of the internal deleteOne() operation on the key vault collection.
deleteKey(id: Binary): DeleteResult;

// Finds a single key document with the given UUID (BSON binary subtype 0x04).
// Returns the result of the internal find() operation on the key vault collection.
getKey(id: Binary): Optional<Document>;

// Finds all documents in the key vault collection.
// Returns the result of the internal find() operation on the key vault collection.
getKeys(): Iterable<Document>;

// Adds a keyAltName to the keyAltNames array of the key document in the key vault collection with the given UUID (BSON binary subtype 0x04).
// Returns the previous version of the key document.
addKeyAltName(id: Binary, keyAltName: String): Optional<Document>;

// Removes a keyAltName from the keyAltNames array of the key document in the key vault collection with the given UUID (BSON binary subtype 0x04).
// Returns the previous version of the key document.
removeKeyAltName(id: Binary, keyAltName: String): Optional<Document>;

// Returns a key document in the key vault collection with the given keyAltName.
getKeyByAltName(keyAltName: String): Optional<Document>;

// Decrypts an encrypted value (BSON binary of subtype 6). Returns the original BSON value.
decrypt(value: Binary): BSONValue;
// 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;

// Decrypts an encrypted value (BSON binary of subtype 6).
jmikola marked this conversation as resolved.
Show resolved Hide resolved
// Returns the original BSON value.
decrypt(value: Binary): BsonValue;

// Implementation details.
private mongocrypt_t libmongocrypt_handle;
Expand All @@ -742,12 +770,19 @@ 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,
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.
and managing data keys in the key vault collection.

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?`_.

When implementing behavior and error handling for key vault functions, Drivers
SHOULD assume the presence of a unique index in the key vault collection on the
``keyAltNames`` field with a partial index filter for only documents where
``keyAltNames`` exists when implementing behavior of key management functions.
Drivers MAY choose to not validate or enforce the existence of the unique index,
addaleax marked this conversation as resolved.
Show resolved Hide resolved
but MUST still be capable of handling errors that such a unique index may yield.

See `Why aren't we creating a unique index in the key vault collection?`_.

DataKeyOpts
-----------

Expand Down Expand Up @@ -1321,7 +1356,7 @@ selection error is propagated to the user.
ClientEncryption
================
The new ClientEncryption type interacts uses libmongocrypt to perform
ClientEncryption.createKey() and ClientEncryption.rewrapManyDataKey(). See the
ClientEncryption operations. See the
`libmongocrypt API documentation <https://github.com/mongodb/libmongocrypt/blob/master/src/mongocrypt.h.in>`_
for more information.

Expand All @@ -1338,13 +1373,13 @@ 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 key management functions.

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 key management functions that require creating, updating, or deleting key
documents in the key vault collection, the corresponding operations MUST be done
with write 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.
key documents from the key vault collection, the corresponding operations 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
Expand Down Expand Up @@ -1938,12 +1973,15 @@ little as possible.
Why aren't we creating a unique index in the key vault collection?
------------------------------------------------------------------

There should be a unique index on keyAltNames. Although GridFS
There should be a unique index on the ``keyAltNames`` field with a partial index
filter for only documents where ``keyAltNames`` exists. Although GridFS
automatically creates indexes as a convenience upon first write, it has
been problematic before. It requires the createIndex privilege, which a
been problematic before due to requiring the ``createIndex`` privilege, which a
jmikola marked this conversation as resolved.
Show resolved Hide resolved
user might not have if they are just querying the key vault collection
with find and adding keys with insert.

See also https://www.mongodb.com/docs/manual/reference/privilege-actions/#mongodb-authaction-createIndex.

Why do operations on views fail?
--------------------------------

Expand Down Expand Up @@ -2222,6 +2260,7 @@ Changelog
:align: left

Date, Description
22-05-24, Add key management API functions
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."
Expand Down
57 changes: 57 additions & 0 deletions source/client-side-encryption/tests/README.rst
Expand Up @@ -1779,3 +1779,60 @@ Use ``clientEncryption`` to encrypt the value "encrypted unindexed value" with t
Store the result in ``payload``.

Use ``clientEncryption`` to decrypt ``payload``. Assert the returned value equals "encrypted unindexed value".

13. Unique Index on keyAltNames
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Setup
`````

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

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

3. Using ``client``, create a unique index on ``keyAltNames`` with a partial index filter for only documents where ``keyAltNames`` exists using writeConcern "majority".

The command should be equivalent to:

.. code:: typescript

db.runCommand(
{
createIndexes: "datakeys",
indexes: [
{
name: "keyAltNames_1",
key: { "keyAltNames": 1 },
unique: true,
partialFilterExpression: { keyAltNames: { $exists: true } }
}
],
writeConcern: { w: "majority" }
}
)

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

5. Using ``client_encryption``, create a data key with a ``local`` KMS provider and the keyAltName "def".

Case 1: createKey()
```````````````````

1. Use ``client_encryption`` to create a new local data key with a keyAltName "abc" and assert the operation does not fail.

2. Repeat Step 1 and assert the operation fails due to a duplicate key server error (error code 11000).

3. Use ``client_encryption`` to create a new local data key with a keyAltName "def" and assert the operation fails due to a duplicate key server error (error code 11000).

Case 2: addKeyAltName()
```````````````````````

1. Use ``client_encryption`` to create a new local data key and assert the operation does not fail.

2. Use ``client_encryption`` to add a keyAltName "abc" to the key created in Step 1 and assert the operation does not fail.

3. Repeat Step 2 and assert the operation does not fail.

4. Use ``client_encryption`` to add a keyAltName "def" to the key created in Step 1 and assert the operation fails due to a duplicate key server error (error code 11000).

5. Use ``client_encryption`` to add a keyAltName "def" to the existing key and assert the operation does not fail.