From b9ac1d4071eefc349809fe9c26059cdd202d37c7 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 7 Dec 2021 16:10:05 +0100 Subject: [PATCH 01/73] feat(NODE-3777): add csfle kmip support --- .evergreen/run-tests.sh | 4 +- src/deps.ts | 11 + .../corpus/corpus-encrypted.json | 1830 +++++++++++++++++ .../corpus/corpus-key-kmip.json | 32 + .../corpus/corpus-schema.json | 1266 ++++++++++++ .../client-side-encryption/corpus/corpus.json | 1662 +++++++++++++++ .../tests/azureKMS.json | 14 + .../client-side-encryption/tests/azureKMS.yml | 2 +- .../client-side-encryption/tests/gcpKMS.json | 14 + .../client-side-encryption/tests/gcpKMS.yml | 2 +- .../client-side-encryption/tests/kmipKMS.json | 223 ++ .../client-side-encryption/tests/kmipKMS.yml | 46 + 12 files changed, 5103 insertions(+), 3 deletions(-) create mode 100644 test/spec/client-side-encryption/corpus/corpus-key-kmip.json create mode 100644 test/spec/client-side-encryption/tests/kmipKMS.json create mode 100644 test/spec/client-side-encryption/tests/kmipKMS.yml diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index d269ae43d45..771a2a427ff 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -41,7 +41,9 @@ if [[ -z "${CLIENT_ENCRYPTION}" ]]; then unset AWS_ACCESS_KEY_ID; unset AWS_SECRET_ACCESS_KEY; else - npm install mongodb-client-encryption@">=2.0.0-beta.0" + if [[ ! -d ${PROJECT_DIRECTORY}/node_modules/mongodb-client-encryption ]]; then + npm install mongodb-client-encryption@">=2.0.0-beta.0" + fi pip install --upgrade boto3 # Get access to the AWS temporary credentials: diff --git a/src/deps.ts b/src/deps.ts index be1f386c0a1..9d6fa769fbb 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -234,6 +234,17 @@ export interface AutoEncryptionOptions { */ endpoint?: string | undefined; }; + /** + * Configuration options for using 'kmip' as your KMS provider + */ + kmip?: { + /** + * The output endpoint string. + * The endpoint consists of a hostname and port separated by a colon. + * E.g. "example.com:123". A port is always present. + */ + endpoint?: string; + }; }; /** * A map of namespaces to a local JSON schema for encryption diff --git a/test/spec/client-side-encryption/corpus/corpus-encrypted.json b/test/spec/client-side-encryption/corpus/corpus-encrypted.json index a11682688a3..1b72aa8a390 100644 --- a/test/spec/client-side-encryption/corpus/corpus-encrypted.json +++ b/test/spec/client-side-encryption/corpus/corpus-encrypted.json @@ -7681,5 +7681,1835 @@ "value": { "$maxKey": 1 } + }, + "kmip_double_rand_auto_id": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAB1hL/nPkpQtqxQUANbIJr30PQ98vPvaoy4JWUoElOL+cCnrSra3o7W+12dydy0rCS2EKrVm7Fw0C8L9nf1hpWjw==", + "subType": "06" + } + } + }, + "kmip_double_rand_auto_altname": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAABxlcphy2SxXlkRBvO1Z3nNUqchmeOhIhkdYBbbW7CwYeLVRDciXFsZN73Nb9Bm+W4IpUNpo6mqFEtfjevIjtFyg==", + "subType": "06" + } + } + }, + "kmip_double_rand_explicit_id": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAABx5AfRSiblFc1DGwxRIaUSP2kaM76ryzPUKL9KnEgnX1kjIlFz5B15uMht2cxdrntHFe1qZZk8V9PxTBpWZhJ8Q==", + "subType": "06" + } + } + }, + "kmip_double_rand_explicit_altname": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAABXUC9v9HPrmU9tINzFmr2sQM9f7GHDus+y5T4pWX28PRtfnTysN/ANCfB9RosoR/wuKsbznwwD2JfSzOvlKo3PQ==", + "subType": "06" + } + } + }, + "kmip_double_det_explicit_id": { + "kms": "kmip", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDouble": "1.2339999999999999858" + } + }, + "kmip_double_det_explicit_altname": { + "kms": "kmip", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDouble": "1.2339999999999999858" + } + }, + "kmip_string_rand_auto_id": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAACGHmqW1qbfqVlfB0x0CkXCk9smhs3yXsxJ/8eypSgbDQqVLSW2nf5bbHpnoCHHNtQ7I7ZBXzPzDLH2GgMJpopeQ==", + "subType": "06" + } + } + }, + "kmip_string_rand_auto_altname": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAC9BJTD1pEMbslAjbJYt7yx/jzKkcZF3axu96+NYwp8afUCjXG5TOUZzODOwkbJuWgr7DBxa2GkZTvaAEk86h+Ow==", + "subType": "06" + } + } + }, + "kmip_string_rand_explicit_id": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAACQlG28ECy8KHXC7GEPdC8+raBo2RMJwl5pofcPaTGkPUEbkreguMd1mYctNb90vXxby1nNeJY4o5zJJCMiNhNXg==", + "subType": "06" + } + } + }, + "kmip_string_rand_explicit_altname": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAACbWuK+3nzeKSNVjmgHb0Ii7rA+CsAd+gYubPiMiHXZwE/o6i9FYWN+t/VK3p4K0CwIi6q3cycrMb2IgcvM27Q7Q==", + "subType": "06" + } + } + }, + "kmip_string_det_auto_id": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAC5OZgr9keCXOIj5Fi06i4win1xt7gpsyPA4Os+HdFn1MIP9tnktvWNRb8Rqhuj2O9KO83brx74Hu3EQ4nT6uCMw==", + "subType": "06" + } + } + }, + "kmip_string_det_explicit_id": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAC5OZgr9keCXOIj5Fi06i4win1xt7gpsyPA4Os+HdFn1MIP9tnktvWNRb8Rqhuj2O9KO83brx74Hu3EQ4nT6uCMw==", + "subType": "06" + } + } + }, + "kmip_string_det_explicit_altname": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAC5OZgr9keCXOIj5Fi06i4win1xt7gpsyPA4Os+HdFn1MIP9tnktvWNRb8Rqhuj2O9KO83brx74Hu3EQ4nT6uCMw==", + "subType": "06" + } + } + }, + "kmip_object_rand_auto_id": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAADh2nGqaAUwHDRVjqYpj8JAPH7scmiHp1Z9SGBZQ6Fapxm+zWDdTBHyitM9U69BctJ5DaaafyqFOj5yr6sJ+ebJQ==", + "subType": "06" + } + } + }, + "kmip_object_rand_auto_altname": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAD1YhOKyNle4y0Qbeio1HlCULLeTCALCLgKSITd50bilD+oDyqQawixJAwphcdjhLdFzbFwst5RWqpsiWMPHx4hQ==", + "subType": "06" + } + } + }, + "kmip_object_rand_explicit_id": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAADveILoWFgX7AhUWCv8UL52TUa75qHuoNadnTQydJlqd6PVmtRKj+8vS7VwxNWPaH4wB1Tk7emMyFEbZpvvzjxqQ==", + "subType": "06" + } + } + }, + "kmip_object_rand_explicit_altname": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAADB/LN9V/4SROJn+ESHRLM7wwcUltQUx3+LbbYXjPDXiiV14HK76Iyy6ZxJ+M5qC9bRj3afhTKuWLBblB8WwksOg==", + "subType": "06" + } + } + }, + "kmip_object_det_explicit_id": { + "kms": "kmip", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_det_explicit_altname": { + "kms": "kmip", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_array_rand_auto_id": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAEasWXQam8XtOkSO0nEttMCQ0iZ4V8DDmhMKyQDFDsiNHyF2h98Ya/xFv4ZSlbpGWXPBvBATEGgov/PDg2vhVi53y4Pk33RHfY60hABuksp3o=", + "subType": "06" + } + } + }, + "kmip_array_rand_auto_altname": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAEj3A1DYSEHm/3SlEmusA+pewxRPUoZ2NAjs60ioEBlCw9n6yiiB+X8d/w40TKsjZcOSfh05NC0z3gnpqQvrNolkxkvi9dmFiZeiiv5vBZUPI=", + "subType": "06" + } + } + }, + "kmip_array_rand_explicit_id": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAEqeJW+L6lP0bn5QcD0FMI0C8vv2n5kV7SKgqKi1o5mxaxmp3Cjlspf7yumfSiQ5js6G9yJVAvHuxlqv14UFyR9RgXS0PIA8WzsAqkL0sJSw0=", + "subType": "06" + } + } + }, + "kmip_array_rand_explicit_altname": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAEnPlPwy0B1VKuNum1GzkZwQjZia5jNYL5bf/k+PbfhnToTRWGxx8+E3R7XXp6YT/rFkjPlzU8ww9+iZNo2oqNpYuHdrIC8ybhO6HZAlvcERo=", + "subType": "06" + } + } + }, + "kmip_array_det_explicit_id": { + "kms": "kmip", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_det_explicit_altname": { + "kms": "kmip", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_binData=00_rand_auto_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFliNDZ6DmjoVcYQBCKDI9njpBsDELg+TD6XLF7xbZnMaJCCHLHr7w3x2/xFfrFSN44CtGAKOniYPCMAspaxHqOA==", + "subType": "06" + } + } + }, + "kmip_binData=00_rand_auto_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAF/P8LPmHKGgG0l5/Xi7jdkwfxpGPxoY0417suCvN6zjM3JNdufytzkektrm9CbBb1SnZCGYF9c0FCMzFG+tN/dg==", + "subType": "06" + } + } + }, + "kmip_binData=00_rand_explicit_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFWI0N4RbnYdEiFrzNpbRN9p+bSLm8Lthiu4K3/CvBg6GQpLMVQFhjW01Bud0lxpT2ohRnOK+ASUhiFcUU/t/lWQ==", + "subType": "06" + } + } + }, + "kmip_binData=00_rand_explicit_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFQZvAtpY4cjEr1rJWVoUGaZKmzocSJ0muHose7Tk5kRDczjFa4Jcu4hN7JLM9qz2z4g+WJC3KQTdW4ZBXStke/Q==", + "subType": "06" + } + } + }, + "kmip_binData=00_det_auto_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFohIHrvzu8xLxVHsnYEDhZmv8BpEoEtFSjMUQzvBLUInvvTuU/rOzlVL88CkAEII7M3hcvrz8FKY7b7lC1veoYg==", + "subType": "06" + } + } + }, + "kmip_binData=00_det_explicit_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFohIHrvzu8xLxVHsnYEDhZmv8BpEoEtFSjMUQzvBLUInvvTuU/rOzlVL88CkAEII7M3hcvrz8FKY7b7lC1veoYg==", + "subType": "06" + } + } + }, + "kmip_binData=00_det_explicit_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFohIHrvzu8xLxVHsnYEDhZmv8BpEoEtFSjMUQzvBLUInvvTuU/rOzlVL88CkAEII7M3hcvrz8FKY7b7lC1veoYg==", + "subType": "06" + } + } + }, + "kmip_binData=04_rand_auto_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFn7rhdO8tYq77uVxcqd9Qjz84Yg7JnJMYf0ULTMTh1vJHacckkhXw+8fIMMiAKwuOVwGkMAtu5RBvrFqdfxryCg8RLTxu1YYVthufiClEIS0=", + "subType": "06" + } + } + }, + "kmip_binData=04_rand_auto_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFwwXQx9dKyoyHq7GBMmHzYe9ysoJK/f/ZWzA6nErau9MtX1gqi7VRsYqkamb47/zVbsLZwPMmdgNyPxEh3kqbV2D61t5RG2A3VeqhO1pTF8c=", + "subType": "06" + } + } + }, + "kmip_binData=04_rand_explicit_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFALeGeinJ8DE+WZniLdCIW2gfJUj445Ukp9PvRLgBXLGedl8mIXlLF2eu3BA9vP6s5y9w6peQjhn+oEofrsUVYD2duyzeIRMKgNiNchjf6TU=", + "subType": "06" + } + } + }, + "kmip_binData=04_rand_explicit_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAF06Fx8CO3OSKE3fGri0VwK0e22YiG9LH2QkDTsRdFbT2lBm+bDD9FrEY8vKWS5RljMuysaxjBOzZ98d2LEs6k8LMOm83Nz/RESe4ZbbcfdQ0=", + "subType": "06" + } + } + }, + "kmip_binData=04_det_auto_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFzmZI909fJgxOykJtvOlv5LsX8z6BxUX2Xg5TsIwOxJMPSC8usm/zR7sZawoVBOuJxtNVLY/8oNP/4pFtAmQo02bUOtTo1yxNz/IZa9x+Q5E=", + "subType": "06" + } + } + }, + "kmip_binData=04_det_explicit_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFzmZI909fJgxOykJtvOlv5LsX8z6BxUX2Xg5TsIwOxJMPSC8usm/zR7sZawoVBOuJxtNVLY/8oNP/4pFtAmQo02bUOtTo1yxNz/IZa9x+Q5E=", + "subType": "06" + } + } + }, + "kmip_binData=04_det_explicit_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFzmZI909fJgxOykJtvOlv5LsX8z6BxUX2Xg5TsIwOxJMPSC8usm/zR7sZawoVBOuJxtNVLY/8oNP/4pFtAmQo02bUOtTo1yxNz/IZa9x+Q5E=", + "subType": "06" + } + } + }, + "kmip_undefined_rand_explicit_id": { + "kms": "kmip", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_rand_explicit_altname": { + "kms": "kmip", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_det_explicit_id": { + "kms": "kmip", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_det_explicit_altname": { + "kms": "kmip", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_objectId_rand_auto_id": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAHZFzE908RuO5deEt3t2QQdT12ybwqbm8D+sMJrdKt2Wp4kVPsw4ocAGGsRYN6VXe46P5fmyG5HqVWn0hkflZnQg==", + "subType": "06" + } + } + }, + "kmip_objectId_rand_auto_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAH3dPKyCCStvOtVGzlgIS33fsl8OAwQblt9i21pOVuLiliY1Tup9EtkSic88+nNEtXnq9gRknRzLthXv/k1ql+7Q==", + "subType": "06" + } + } + }, + "kmip_objectId_rand_explicit_id": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAHcEjxVfHDSfLzFxAuK/rs/Pn/XV7jLkgKXZYeY0PNlRi1MHojN2AvQqI3J2rOvAjuYfikGcpvGPp/goqUbV9HYw==", + "subType": "06" + } + } + }, + "kmip_objectId_rand_explicit_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAHX65sNHnRYpx3VbWPCdQyFe7u0Y5ItabLEduqDeVsPk/iK4X3GjCSHQfw1yPi+CA+/veVpgdonwws6RiYV4ZZ5Q==", + "subType": "06" + } + } + }, + "kmip_objectId_det_auto_id": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAHKU7mcdGEq2WGrDB6TicipLQstAk6G3PkiNt5F3bMavpKLjz04UBrd8aWGVG2gJTTON1UKRztiYFgRvb8f+LK/Q==", + "subType": "06" + } + } + }, + "kmip_objectId_det_explicit_id": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAHKU7mcdGEq2WGrDB6TicipLQstAk6G3PkiNt5F3bMavpKLjz04UBrd8aWGVG2gJTTON1UKRztiYFgRvb8f+LK/Q==", + "subType": "06" + } + } + }, + "kmip_objectId_det_explicit_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAHKU7mcdGEq2WGrDB6TicipLQstAk6G3PkiNt5F3bMavpKLjz04UBrd8aWGVG2gJTTON1UKRztiYFgRvb8f+LK/Q==", + "subType": "06" + } + } + }, + "kmip_bool_rand_auto_id": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAIw/xgJlKEvErmVtue3X3RFsOI2sttAbxnzh1INc9GUQ2vok1VwYt9k88RxMPiOwMAZG7P1MlAdx7zt865onPKOw==", + "subType": "06" + } + } + }, + "kmip_bool_rand_auto_altname": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAIn8IuzlNHbpTgXOd1wEp364zJOBxj2Zf7a9B5osUV1sDY0G1OVpEnuDvZeUsdiUSyRjTTxzyuD/KZlKZ3+qrnrA==", + "subType": "06" + } + } + }, + "kmip_bool_rand_explicit_id": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAI3Nz9PdjUYQRGfTtvYSR8EQuUKFL0wdlEdfSCTBmMBhBPuuF9KxqCgy+ldVu1DRRgg3346DOKEEtE9BJPPInJ6Q==", + "subType": "06" + } + } + }, + "kmip_bool_rand_explicit_altname": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAIEGjqoerIZBk8Rw+YTO7jFKWzagDS8mEpD+9Wm1Q0r0ZHUmV0dQZcIqRV4oUk8U8uHUn0N3t2qGLr+rhUs4GH/g==", + "subType": "06" + } + } + }, + "kmip_bool_det_explicit_id": { + "kms": "kmip", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "kmip_bool_det_explicit_altname": { + "kms": "kmip", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "kmip_date_rand_auto_id": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAJgr0v4xetUXjlLcPcyKv/rzjtWOKp9CZJcm23Noglu5RR/rXJS0qKI+W9MmJ64TMf27KvaJ0UXwfTRrvOC1plCg==", + "subType": "06" + } + } + }, + "kmip_date_rand_auto_altname": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAJoeysAaiPsVK+JL1P1vD/9xF92m5kKidUdn6yklPlSKN4VVEBTymDetTLujULs1u1TlrS71jVLxo3xEwpG/KQvg==", + "subType": "06" + } + } + }, + "kmip_date_rand_explicit_id": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAJVwu4+Su0DktpnZvzTBHYpWbWTq5gho/SLijrcIrFJcvq4YrjjPCXv+odCl95tkH+J1RlJdQ5Cr0umEIazLa6GA==", + "subType": "06" + } + } + }, + "kmip_date_rand_explicit_altname": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAJWTYpjbDkIf82QXHMGrvd0SqhP8cBIakfYJf5aNcNrs86vxRhiG3KwETWPeOOlPZ6n1WjE2bOLB+DJTAxmJvahA==", + "subType": "06" + } + } + }, + "kmip_date_det_auto_id": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAJ/+sQrUqQh+JADSVIKM0d68gDUhDy37M1z1uvROzQw6hUAbQeD0DWdztADKg560UTPM4uOgH4NAyhLyBLMrWWHg==", + "subType": "06" + } + } + }, + "kmip_date_det_explicit_id": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAJ/+sQrUqQh+JADSVIKM0d68gDUhDy37M1z1uvROzQw6hUAbQeD0DWdztADKg560UTPM4uOgH4NAyhLyBLMrWWHg==", + "subType": "06" + } + } + }, + "kmip_date_det_explicit_altname": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAJ/+sQrUqQh+JADSVIKM0d68gDUhDy37M1z1uvROzQw6hUAbQeD0DWdztADKg560UTPM4uOgH4NAyhLyBLMrWWHg==", + "subType": "06" + } + } + }, + "kmip_null_rand_explicit_id": { + "kms": "kmip", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "kmip_null_rand_explicit_altname": { + "kms": "kmip", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "kmip_null_det_explicit_id": { + "kms": "kmip", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "kmip_null_det_explicit_altname": { + "kms": "kmip", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "kmip_regex_rand_auto_id": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAALi8avMfpxSlDsSTqdxO8O2B1M79gOElyUIdXySQo7mvgHlf4oHQ7r94lL9dnsA2t/jmUmBKoGypaUQUSQE+9x+A==", + "subType": "06" + } + } + }, + "kmip_regex_rand_auto_altname": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAALfHerZ/KolaBrb5qi3SpeNVW+i/nh5mkcdtQg5f1pHePr68KryHucM/XDAzbMqrPlag2/41STGYdJqzYO7Mbppg==", + "subType": "06" + } + } + }, + "kmip_regex_rand_explicit_id": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAALOhKDVAN5cuDyB1EuRFWgKKt0wGJ63E5pPY8Tq2TXMNgCxUUc5O+TE+Ux4ls/uMyOBA3gPzND0CZKiru0i7ACUQ==", + "subType": "06" + } + } + }, + "kmip_regex_rand_explicit_altname": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAALK3Hg8xX9gX+d3vKh7aosRP9CS2CIFeG9sapZv3OAPv1eWjY62Cp/G16kJ0BQt33RYD+DzD3gWupfUSyNZR0gng==", + "subType": "06" + } + } + }, + "kmip_regex_det_auto_id": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAALaQXA8rItT7ELVxO8XtAWdHuiXFFPmnMhS5PMrUy/6mRtbq4fvU9dascW7ozonKOh8ad6+MIT7B/STv9dVBF4Kw==", + "subType": "06" + } + } + }, + "kmip_regex_det_explicit_id": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAALaQXA8rItT7ELVxO8XtAWdHuiXFFPmnMhS5PMrUy/6mRtbq4fvU9dascW7ozonKOh8ad6+MIT7B/STv9dVBF4Kw==", + "subType": "06" + } + } + }, + "kmip_regex_det_explicit_altname": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAALaQXA8rItT7ELVxO8XtAWdHuiXFFPmnMhS5PMrUy/6mRtbq4fvU9dascW7ozonKOh8ad6+MIT7B/STv9dVBF4Kw==", + "subType": "06" + } + } + }, + "kmip_dbPointer_rand_auto_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAMoGkfmmUWTI+0aW7jVyCJ5Dgru1SCXBUmJSRzDL0D57pNruQ+79tVVcI6Uz5j87DhZFxShHbPjj583vLOOBNM3WGzZCpqH3serhHTWvXK+NM=", + "subType": "06" + } + } + }, + "kmip_dbPointer_rand_auto_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAMwu1WaRhhv43xgxLNxuenbND9M6mxGtCs9o4J5+yfL95XNB9Daie3RcLlyngz0pncBie6IqjhTycXsxTLQ94Jdg6m5GD5cU541LYKvhbv5f4=", + "subType": "06" + } + } + }, + "kmip_dbPointer_rand_explicit_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAM+CIoCAisUwhhJtWQLolxQGQWafniwYyvaJQHmJC94Uwbf1gPfhMR42v2VtrmIVP0J0BaP/xf0cco2/qWRdKGZpgkK2CK6M972NtnZ/2x03A=", + "subType": "06" + } + } + }, + "kmip_dbPointer_rand_explicit_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAMjbeE9+EaJYjGfeAuxsV8teOdsW8bfnlkvji/tE11Zq89UMGx+oUsZzeLjUgVZ5nxsZKCZjEAq+DPnwFVC+MgqNeqWL7fRChODFlPGH2ZC+8=", + "subType": "06" + } + } + }, + "kmip_dbPointer_det_auto_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAM5B+fjbjYCZzCYUu4N/pJI3srCCXN+OCCHweeweqmpIEmB7yw87bQRIMGtCm6HuekcZ5J5q+nY5AQb0du/wh1YIoOrC3u4w7ZcLHkDmuAJPg=", + "subType": "06" + } + } + }, + "kmip_dbPointer_det_explicit_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAM5B+fjbjYCZzCYUu4N/pJI3srCCXN+OCCHweeweqmpIEmB7yw87bQRIMGtCm6HuekcZ5J5q+nY5AQb0du/wh1YIoOrC3u4w7ZcLHkDmuAJPg=", + "subType": "06" + } + } + }, + "kmip_dbPointer_det_explicit_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAM5B+fjbjYCZzCYUu4N/pJI3srCCXN+OCCHweeweqmpIEmB7yw87bQRIMGtCm6HuekcZ5J5q+nY5AQb0du/wh1YIoOrC3u4w7ZcLHkDmuAJPg=", + "subType": "06" + } + } + }, + "kmip_javascript_rand_auto_id": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAANuzlkWs/c8xArrAxPgYuCeShjj1zCfIMHOTPohspcyNofo9iY3P5MlhEOprZDiS8dBFg6EB7fZDzDdczx6VCN2A==", + "subType": "06" + } + } + }, + "kmip_javascript_rand_auto_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAANwJ72y7UqCBJh1NwVRiE3vU1ex7FMv/X5YWCMuO9MHPMo4g1V5eaO4KfOr+K8+9NtkflgMpeDkvwP92rfR5ud5Q==", + "subType": "06" + } + } + }, + "kmip_javascript_rand_explicit_id": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAANj5q+888itRnLsw9PNGsBLhgqpvem5IJBOE2292r6zwjVueoEK/2I2PesRnn0esnkwdia1ADoMkcLUegwcFRkWQ==", + "subType": "06" + } + } + }, + "kmip_javascript_rand_explicit_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAANnvbnmApys7OIe8LGTsZKDG1F1G1SI/rfZVmF6q1fq5U7feYPp1ejb2t2S2+v7LfcOHytsQWGcYuWCDcl+vosvQ==", + "subType": "06" + } + } + }, + "kmip_javascript_det_auto_id": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAANOR9R/Da8j5iVxllLiGFlv4U/bVn/PyN9/5WeGJkGJeE/j/osKrKx6IL1igI0YVI+pKKzsINqJGIv+bJX0s7MNw==", + "subType": "06" + } + } + }, + "kmip_javascript_det_explicit_id": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAANOR9R/Da8j5iVxllLiGFlv4U/bVn/PyN9/5WeGJkGJeE/j/osKrKx6IL1igI0YVI+pKKzsINqJGIv+bJX0s7MNw==", + "subType": "06" + } + } + }, + "kmip_javascript_det_explicit_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAANOR9R/Da8j5iVxllLiGFlv4U/bVn/PyN9/5WeGJkGJeE/j/osKrKx6IL1igI0YVI+pKKzsINqJGIv+bJX0s7MNw==", + "subType": "06" + } + } + }, + "kmip_symbol_rand_auto_id": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAOe+vXpJSkmBM3WkxZrn4ea9/C6iNyMXWUzkQIzIYlnbkyu8od8nfOdhobUhoFxcKnvdaxN1s5NhJ1FA97RN/upGYN+AI/7cTCElmFSpdSvkI=", + "subType": "06" + } + } + }, + "kmip_symbol_rand_auto_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAOPpCgK6Hc/M2elOJkwIU9J7PZa+h1chody2yvfDu/UlB6T5sxnEZ6aEY/ISNLhJlhsRzuApSgFOmnrcG6Eg9VnSKin2yK0ll+VFxQEDHAcSA=", + "subType": "06" + } + } + }, + "kmip_symbol_rand_explicit_id": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAOVoHX9GaOn71L5D9TpZmmxkx/asr0FHCLG5ZgLLA04yIhZHsDjt2DiVGGO/Mf4KwvoBn7Cf08qMhW7rQh2LgvvSLBO3zbw5l+MZ/bSn+Jylo=", + "subType": "06" + } + } + }, + "kmip_symbol_rand_explicit_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAOPobmcO/I4QObtCUEmGWpSCJ6tlYyhbO59q78LZBucSNl7DSkf/13tOJ9t+WKXACcMKVMmfPoFsgHbVj1nKWULBT07n1OWWDTZkuMD6C2+Fc=", + "subType": "06" + } + } + }, + "kmip_symbol_det_auto_id": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAOPpwX4mafoQJYHuzYfbKW1JunpjpB7Nd2slTC3n8Hsas9wQYf9VkModQhe5M4wZHOIXpehaODRcjKKfKRmpnNBOURSLm/ORJvy+UxtSLsnqo=", + "subType": "06" + } + } + }, + "kmip_symbol_det_explicit_id": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAOPpwX4mafoQJYHuzYfbKW1JunpjpB7Nd2slTC3n8Hsas9wQYf9VkModQhe5M4wZHOIXpehaODRcjKKfKRmpnNBOURSLm/ORJvy+UxtSLsnqo=", + "subType": "06" + } + } + }, + "kmip_symbol_det_explicit_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAOPpwX4mafoQJYHuzYfbKW1JunpjpB7Nd2slTC3n8Hsas9wQYf9VkModQhe5M4wZHOIXpehaODRcjKKfKRmpnNBOURSLm/ORJvy+UxtSLsnqo=", + "subType": "06" + } + } + }, + "kmip_javascriptWithScope_rand_auto_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAPW2VMMm+EvsYpVtJQhsxgxgvV35kr9nxqKxP2qqIOAOQ58R/1oyYScFkNwB/tw0A1/zdvhoo+ERa7c0tjLIojFrosXhX2N/8Z4VnbZruz0Nk=", + "subType": "06" + } + } + }, + "kmip_javascriptWithScope_rand_auto_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAPjPq9BQR4EwG/CD+RthOJY04m99LCl/shY6HnaU/QL627kN1dbBAG5vs+MXfa+glg8waVTNgB94vm3j72FMV1ZOKvbl4faWF1Rl2EOpOlR9U=", + "subType": "06" + } + } + }, + "kmip_javascriptWithScope_rand_explicit_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAPtqebrCAidKzBMvp3B5/vBeetqeCoMKS+vo+hLAYooXrnBunWxwRHpr45XYUvroG3aqOMkLtVZSgw8sO6Y/3z1viO2G0sGQW1ZMoW0/PX5Uw=", + "subType": "06" + } + } + }, + "kmip_javascriptWithScope_rand_explicit_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAPtkJwXKlq8Fx1f1+9HFofM4uKi6lHQRFRyiOyUFJYxxZY1LR/2WXXTqWz3MWtrcJFCB+QSVOb1N/ieC7AZUboPgIuPJISM3Hu5VU2x/Isbdc=", + "subType": "06" + } + } + }, + "kmip_javascriptWithScope_det_explicit_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_det_explicit_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_int_rand_auto_id": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAQ50kE7Tby9od2OsmIGZhp9k/mj4vy/YdnmF6YsSPxihbjV1vXGMraI/nGCr+0H1riwzq3m4sCT7aPw2VgiuwKMA==", + "subType": "06" + } + } + }, + "kmip_int_rand_auto_altname": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAQkNL14OSMX/bJbsLtB/UumRoat6QOY7fvwZxRrkXTS3VJVHigthI1cUX7Is/uUsY8oHOfk/ZuHklQkifmfdcklQ==", + "subType": "06" + } + } + }, + "kmip_int_rand_explicit_id": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAQtN2gNVU9Itoj+vgcK/4jEB5baSUH+Qz2WqTY7m0XaA3bPWGFCiWY4Sdw+qovednrSSSbC+azWi1QYclFRraldQ==", + "subType": "06" + } + } + }, + "kmip_int_rand_explicit_altname": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAQk6uBqwXXFF9zEM4bc124goI3pBy2Jdi8Cd0ycKkjXrPG7GVCUm2UMbO+zEzYODeVo35N11g2yMXcv9RVgjWtNA==", + "subType": "06" + } + } + }, + "kmip_int_det_auto_id": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAQgrkPEf+RBZMn/J7HZObqEfus8icYls6ecaUrlabI6v1ALgxLuv23WSIfTr6mqpQCounqdA14DWS/Wl3kSkVC0w==", + "subType": "06" + } + } + }, + "kmip_int_det_explicit_id": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAQgrkPEf+RBZMn/J7HZObqEfus8icYls6ecaUrlabI6v1ALgxLuv23WSIfTr6mqpQCounqdA14DWS/Wl3kSkVC0w==", + "subType": "06" + } + } + }, + "kmip_int_det_explicit_altname": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAQgrkPEf+RBZMn/J7HZObqEfus8icYls6ecaUrlabI6v1ALgxLuv23WSIfTr6mqpQCounqdA14DWS/Wl3kSkVC0w==", + "subType": "06" + } + } + }, + "kmip_timestamp_rand_auto_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAR2Cu3o2e/u5o69MndeZPJU5ngVA1G2MNYn00t+up/GlmaUC1ni1CVl0ZR0EVZ0gCDUrfxwPISPib8y23tNjbsog==", + "subType": "06" + } + } + }, + "kmip_timestamp_rand_auto_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAARgi8stgSQwqnN4Ws2ZBILOREsjreZcS1MBerL7dbGLVfzW99tqECglhGokkrE0aY69L0xMgcAUIaFRN4GanQAPg==", + "subType": "06" + } + } + }, + "kmip_timestamp_rand_explicit_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAARPxEEI8L5Q3Jybu88BLdf31T3uYEUbijgSlKlkTt141RYrlE8nxtiYU5/5H9GXBis0Qq1s2C+MauD2h/cNijTCA==", + "subType": "06" + } + } + }, + "kmip_timestamp_rand_explicit_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAARh/QaU1dnGbii4LtXCpT5o6vencc8E2fzarjJFbSEd0ixW/UV1ppZdvD729d0umkaIwIEVA4q+XVvHfl/ckKPFg==", + "subType": "06" + } + } + }, + "kmip_timestamp_det_auto_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAARqdpLb72mmzb75QBrE+ATMfS5LLqzAD/1g5ScT8zfgh0IHsZZBWCJlSVRNC12Sgr3zdXHMtYp8C3OZT6/tPkQGg==", + "subType": "06" + } + } + }, + "kmip_timestamp_det_explicit_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAARqdpLb72mmzb75QBrE+ATMfS5LLqzAD/1g5ScT8zfgh0IHsZZBWCJlSVRNC12Sgr3zdXHMtYp8C3OZT6/tPkQGg==", + "subType": "06" + } + } + }, + "kmip_timestamp_det_explicit_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAARqdpLb72mmzb75QBrE+ATMfS5LLqzAD/1g5ScT8zfgh0IHsZZBWCJlSVRNC12Sgr3zdXHMtYp8C3OZT6/tPkQGg==", + "subType": "06" + } + } + }, + "kmip_long_rand_auto_id": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAASVv+ClXkh9spIaXWJYRV/o8UZjG+WWWrNpIjZ9LQn2bXakrKJ3REvdkrzGuxASmBhBYTplEyvxVCJwXuWRAGGYw==", + "subType": "06" + } + } + }, + "kmip_long_rand_auto_altname": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAASeAz/dK+Gc4/jx3W07B2rNFvQ0LoyCllFRvRVGu1Xf1NByc4cRZLOMzlr99syz/fifF6WY30bOi5Pani9QtFuGg==", + "subType": "06" + } + } + }, + "kmip_long_rand_explicit_id": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAASP1HD9uoDlwTldaznKxW71JUQcLsa4/cUWzeTnelQwdpohCbZsM8fBZBqgwwTWnjpYY/LBUipC6yhwLKfUXBoBQ==", + "subType": "06" + } + } + }, + "kmip_long_rand_explicit_altname": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAASnGPH77bS/ETB1hn+VTvsBrxEvIHA6EAb8Z2SEz6BHt7SVeI+I7DLERvRVpV5kNJFcKgXDrvRmD+Et0rhSmk9sw==", + "subType": "06" + } + } + }, + "kmip_long_det_auto_id": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAS+zKmtijSTPOEVlpwmaeMIOuzVNuZpV4Jw9zP8Yqa1xYtlItXDozqdibacRaA74KU49KNySdR1T7fxwxa2OOTrQ==", + "subType": "06" + } + } + }, + "kmip_long_det_explicit_id": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAS+zKmtijSTPOEVlpwmaeMIOuzVNuZpV4Jw9zP8Yqa1xYtlItXDozqdibacRaA74KU49KNySdR1T7fxwxa2OOTrQ==", + "subType": "06" + } + } + }, + "kmip_long_det_explicit_altname": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAS+zKmtijSTPOEVlpwmaeMIOuzVNuZpV4Jw9zP8Yqa1xYtlItXDozqdibacRaA74KU49KNySdR1T7fxwxa2OOTrQ==", + "subType": "06" + } + } + }, + "kmip_decimal_rand_auto_id": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAATu/BbCc5Ti9SBlMR2B8zj3Q1yQ16Uob+10LWaT5QKS192IcnBGy4wmmNkIsTys060xUby9KKQF80dVPnjYfqJwEXCe/pVaPQZftE0DolKv78=", + "subType": "06" + } + } + }, + "kmip_decimal_rand_auto_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAATpq6/dtxq2ZUZHrK10aB0YjjPalEaXYcyAyRZjfXWAYCLZdT9sIybjX3Axjxisim+VSHx0QU7oXkKUfcbLgHyjUXj8g9059FHxKFkUsNv4Z8=", + "subType": "06" + } + } + }, + "kmip_decimal_rand_explicit_id": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAATS++9KcfM7uiShZYxRpFPrBJquKv7dyvFRTjnxs6aaaPo0fiqpv6bco/cMLsldEVpWDEA/Tc2HtSXYPp4UJsMfASyBjoxCloL5SaRWyD9Ye8=", + "subType": "06" + } + } + }, + "kmip_decimal_rand_explicit_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAATREcETS5KoAGyj/P45owPrdFfy5ng8Z1ND+F+780lLddOyPeDnIsa7yg6uvhTZ65mHfGLvKcFocclYenq/AX1dY4xdjLRg/AfT088A27ORUA=", + "subType": "06" + } + } + }, + "kmip_decimal_det_explicit_id": { + "kms": "kmip", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_det_explicit_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_minKey_rand_explicit_id": { + "kms": "kmip", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_rand_explicit_altname": { + "kms": "kmip", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_det_explicit_id": { + "kms": "kmip", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_det_explicit_altname": { + "kms": "kmip", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_maxKey_rand_explicit_id": { + "kms": "kmip", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_rand_explicit_altname": { + "kms": "kmip", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_det_explicit_id": { + "kms": "kmip", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_det_explicit_altname": { + "kms": "kmip", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } } } \ No newline at end of file diff --git a/test/spec/client-side-encryption/corpus/corpus-key-kmip.json b/test/spec/client-side-encryption/corpus/corpus-key-kmip.json new file mode 100644 index 00000000000..7c7069700e1 --- /dev/null +++ b/test/spec/client-side-encryption/corpus/corpus-key-kmip.json @@ -0,0 +1,32 @@ +{ + "_id": { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "eUYDyB0HuWb+lQgUwO+6qJQyTTDTY2gp9FbemL7ZFo0pvr0x6rm6Ff9OVUTGH6HyMKipaeHdiIJU1dzsLwvqKvi7Beh+U4iaIWX/K0oEg1GOsJc0+Z/in8gNHbGUYLmycHViM3LES3kdt7FdFSUl5rEBHrM71yoNEXImz17QJWMGOuT4x6yoi2pvnaRJwfrI4DjpmnnTrDMac92jgZehbg==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1634220190041" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1634220190041" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "kmip", + "keyId": "1" + }, + "keyAltNames": ["kmip"] +} \ No newline at end of file diff --git a/test/spec/client-side-encryption/corpus/corpus-schema.json b/test/spec/client-side-encryption/corpus/corpus-schema.json index f145f712a4a..e74bc914f51 100644 --- a/test/spec/client-side-encryption/corpus/corpus-schema.json +++ b/test/spec/client-side-encryption/corpus/corpus-schema.json @@ -5064,6 +5064,1272 @@ "bsonType": "binData" } } + }, + "kmip_double_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "kmip_double_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "kmip_double_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_double_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_string_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "kmip_string_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "kmip_string_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_string_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_string_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "string" + } + } + } + }, + "kmip_string_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_string_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_object_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "kmip_object_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "kmip_object_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_object_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_array_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "kmip_array_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "kmip_array_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_array_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=00_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=00_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=00_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=00_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=00_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=00_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=00_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=04_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=04_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=04_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=04_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=04_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=04_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=04_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_objectId_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "kmip_objectId_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "kmip_objectId_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_objectId_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_objectId_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "objectId" + } + } + } + }, + "kmip_objectId_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_objectId_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_bool_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "kmip_bool_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "kmip_bool_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_bool_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_date_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "kmip_date_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "kmip_date_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_date_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_date_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "date" + } + } + } + }, + "kmip_date_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_date_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_regex_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "kmip_regex_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "kmip_regex_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_regex_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_regex_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "regex" + } + } + } + }, + "kmip_regex_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_regex_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_dbPointer_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "kmip_dbPointer_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "kmip_dbPointer_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_dbPointer_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_dbPointer_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "dbPointer" + } + } + } + }, + "kmip_dbPointer_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_dbPointer_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascript_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "kmip_javascript_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "kmip_javascript_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascript_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascript_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "javascript" + } + } + } + }, + "kmip_javascript_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascript_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_symbol_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "kmip_symbol_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "kmip_symbol_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_symbol_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_symbol_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "symbol" + } + } + } + }, + "kmip_symbol_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_symbol_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascriptWithScope_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "kmip_javascriptWithScope_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "kmip_javascriptWithScope_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascriptWithScope_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_int_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "kmip_int_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "kmip_int_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_int_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_int_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "int" + } + } + } + }, + "kmip_int_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_int_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_timestamp_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "kmip_timestamp_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "kmip_timestamp_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_timestamp_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_timestamp_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "timestamp" + } + } + } + }, + "kmip_timestamp_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_timestamp_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_long_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "kmip_long_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "kmip_long_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_long_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_long_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "long" + } + } + } + }, + "kmip_long_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_long_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_decimal_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "kmip_decimal_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "kmip_decimal_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_decimal_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } } } } \ No newline at end of file diff --git a/test/spec/client-side-encryption/corpus/corpus.json b/test/spec/client-side-encryption/corpus/corpus.json index 55bbaf99c2c..559711b347e 100644 --- a/test/spec/client-side-encryption/corpus/corpus.json +++ b/test/spec/client-side-encryption/corpus/corpus.json @@ -4,6 +4,7 @@ "altname_local": "local", "altname_azure": "azure", "altname_gcp": "gcp", + "altname_kmip": "kmip", "aws_double_rand_auto_id": { "kms": "aws", "type": "double", @@ -6648,6 +6649,1667 @@ "$maxKey": 1 } }, + "kmip_double_rand_auto_id": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_double_rand_auto_altname": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_double_rand_explicit_id": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_double_rand_explicit_altname": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_double_det_explicit_id": { + "kms": "kmip", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_double_det_explicit_altname": { + "kms": "kmip", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_string_rand_auto_id": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_rand_auto_altname": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_rand_explicit_id": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_rand_explicit_altname": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_det_auto_id": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_det_explicit_id": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_det_explicit_altname": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "kmip_object_rand_auto_id": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_rand_auto_altname": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_rand_explicit_id": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_rand_explicit_altname": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_det_explicit_id": { + "kms": "kmip", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_det_explicit_altname": { + "kms": "kmip", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_array_rand_auto_id": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_rand_auto_altname": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_rand_explicit_id": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_rand_explicit_altname": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_det_explicit_id": { + "kms": "kmip", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_det_explicit_altname": { + "kms": "kmip", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_binData=00_rand_auto_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_rand_auto_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_rand_explicit_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_rand_explicit_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_det_auto_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_det_explicit_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_det_explicit_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=04_rand_auto_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_rand_auto_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_rand_explicit_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_rand_explicit_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_det_auto_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_det_explicit_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_det_explicit_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_undefined_rand_explicit_id": { + "kms": "kmip", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_rand_explicit_altname": { + "kms": "kmip", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_det_explicit_id": { + "kms": "kmip", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_det_explicit_altname": { + "kms": "kmip", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_objectId_rand_auto_id": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_rand_auto_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_rand_explicit_id": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_rand_explicit_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_det_auto_id": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_det_explicit_id": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_det_explicit_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_bool_rand_auto_id": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": true + }, + "kmip_bool_rand_auto_altname": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": true + }, + "kmip_bool_rand_explicit_id": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": true + }, + "kmip_bool_rand_explicit_altname": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": true + }, + "kmip_bool_det_explicit_id": { + "kms": "kmip", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "kmip_bool_det_explicit_altname": { + "kms": "kmip", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "kmip_date_rand_auto_id": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_rand_auto_altname": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_rand_explicit_id": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_rand_explicit_altname": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_det_auto_id": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_det_explicit_id": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_det_explicit_altname": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_null_rand_explicit_id": { + "kms": "kmip", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "kmip_null_rand_explicit_altname": { + "kms": "kmip", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "kmip_null_det_explicit_id": { + "kms": "kmip", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "kmip_null_det_explicit_altname": { + "kms": "kmip", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "kmip_regex_rand_auto_id": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_rand_auto_altname": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_rand_explicit_id": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_rand_explicit_altname": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_det_auto_id": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_det_explicit_id": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_det_explicit_altname": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_dbPointer_rand_auto_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_rand_auto_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_rand_explicit_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_rand_explicit_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_det_auto_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_det_explicit_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_det_explicit_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_javascript_rand_auto_id": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_rand_auto_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_rand_explicit_id": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_rand_explicit_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_det_auto_id": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_det_explicit_id": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_det_explicit_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_symbol_rand_auto_id": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_rand_auto_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_rand_explicit_id": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_rand_explicit_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_det_auto_id": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_det_explicit_id": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_det_explicit_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_javascriptWithScope_rand_auto_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_rand_auto_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_rand_explicit_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_rand_explicit_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_det_explicit_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_det_explicit_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_int_rand_auto_id": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_rand_auto_altname": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_rand_explicit_id": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_rand_explicit_altname": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_det_auto_id": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_det_explicit_id": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_det_explicit_altname": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_timestamp_rand_auto_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_rand_auto_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_rand_explicit_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_rand_explicit_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_det_auto_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_det_explicit_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_det_explicit_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_long_rand_auto_id": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_rand_auto_altname": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_rand_explicit_id": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_rand_explicit_altname": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_det_auto_id": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_det_explicit_id": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_det_explicit_altname": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_decimal_rand_auto_id": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_rand_auto_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_rand_explicit_id": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_rand_explicit_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_det_explicit_id": { + "kms": "kmip", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_det_explicit_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_minKey_rand_explicit_id": { + "kms": "kmip", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_rand_explicit_altname": { + "kms": "kmip", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_det_explicit_id": { + "kms": "kmip", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_det_explicit_altname": { + "kms": "kmip", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_maxKey_rand_explicit_id": { + "kms": "kmip", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_rand_explicit_altname": { + "kms": "kmip", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_det_explicit_id": { + "kms": "kmip", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_det_explicit_altname": { + "kms": "kmip", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, "payload=0,algo=rand": { "kms": "local", "type": "string", diff --git a/test/spec/client-side-encryption/tests/azureKMS.json b/test/spec/client-side-encryption/tests/azureKMS.json index f0f5329d700..afecf40b0a7 100644 --- a/test/spec/client-side-encryption/tests/azureKMS.json +++ b/test/spec/client-side-encryption/tests/azureKMS.json @@ -64,6 +64,20 @@ "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } + }, + "encrypted_string_kmip": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "dBHpr8aITfeBQ15grpbLpQ==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } } }, "bsonType": "object" diff --git a/test/spec/client-side-encryption/tests/azureKMS.yml b/test/spec/client-side-encryption/tests/azureKMS.yml index e3e0fc55a4c..b3c1f694720 100644 --- a/test/spec/client-side-encryption/tests/azureKMS.yml +++ b/test/spec/client-side-encryption/tests/azureKMS.yml @@ -4,7 +4,7 @@ database_name: &database_name "default" collection_name: &collection_name "default" data: [] -json_schema: {'properties': {'encrypted_string_aws': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_azure': {'encrypt': {'keyId': [{'$binary': {'base64': 'AZURE+AAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_gcp': {'encrypt': {'keyId': [{'$binary': {'base64': 'GCP+AAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_local': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +json_schema: {'properties': {'encrypted_string_aws': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_azure': {'encrypt': {'keyId': [{'$binary': {'base64': 'AZURE+AAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_gcp': {'encrypt': {'keyId': [{'$binary': {'base64': 'GCP+AAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_local': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_kmip': {'encrypt': {'keyId': [{'$binary': {'base64': 'dBHpr8aITfeBQ15grpbLpQ==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} key_vault_data: [{'_id': {'$binary': {'base64': 'AZURE+AAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'keyMaterial': {'$binary': {'base64': 'n+HWZ0ZSVOYA3cvQgP7inN4JSXfOH85IngmeQxRpQHjCCcqT3IFqEWNlrsVHiz3AELimHhX4HKqOLWMUeSIT6emUDDoQX9BAv8DR1+E1w4nGs/NyEneac78EYFkK3JysrFDOgl2ypCCTKAypkn9CkAx1if4cfgQE93LW4kczcyHdGiH36CIxrCDGv1UzAvERN5Qa47DVwsM6a+hWsF2AAAJVnF0wYLLJU07TuRHdMrrphPWXZsFgyV+lRqJ7DDpReKNO8nMPLV/mHqHBHGPGQiRdb9NoJo8CvokGz4+KE8oLwzKf6V24dtwZmRkrsDV4iOhvROAzz+Euo1ypSkL3mw==', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1601573901680'}}, 'updateDate': {'$date': {'$numberLong': '1601573901680'}}, 'status': {'$numberInt': '0'}, 'masterKey': {'provider': 'azure', 'keyVaultEndpoint': 'key-vault-csfle.vault.azure.net', 'keyName': 'key-name-csfle'}, 'keyAltNames': ['altname', 'azure_altname']}] tests: diff --git a/test/spec/client-side-encryption/tests/gcpKMS.json b/test/spec/client-side-encryption/tests/gcpKMS.json index 297d5d0dc8e..c2c08b8a232 100644 --- a/test/spec/client-side-encryption/tests/gcpKMS.json +++ b/test/spec/client-side-encryption/tests/gcpKMS.json @@ -64,6 +64,20 @@ "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } + }, + "encrypted_string_kmip": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "dBHpr8aITfeBQ15grpbLpQ==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } } }, "bsonType": "object" diff --git a/test/spec/client-side-encryption/tests/gcpKMS.yml b/test/spec/client-side-encryption/tests/gcpKMS.yml index 736d9684dfc..50b6a40bec8 100644 --- a/test/spec/client-side-encryption/tests/gcpKMS.yml +++ b/test/spec/client-side-encryption/tests/gcpKMS.yml @@ -4,7 +4,7 @@ database_name: &database_name "default" collection_name: &collection_name "default" data: [] -json_schema: {'properties': {'encrypted_string_aws': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_azure': {'encrypt': {'keyId': [{'$binary': {'base64': 'AZURE+AAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_gcp': {'encrypt': {'keyId': [{'$binary': {'base64': 'GCP+AAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_local': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +json_schema: {'properties': {'encrypted_string_aws': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_azure': {'encrypt': {'keyId': [{'$binary': {'base64': 'AZURE+AAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_gcp': {'encrypt': {'keyId': [{'$binary': {'base64': 'GCP+AAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_local': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_kmip': {'encrypt': {'keyId': [{'$binary': {'base64': 'dBHpr8aITfeBQ15grpbLpQ==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} key_vault_data: [{'_id': {'$binary': {'base64': 'GCP+AAAAAAAAAAAAAAAAAA==', 'subType': '04'}}, 'keyMaterial': {'$binary': {'base64': 'CiQAIgLj0WyktnB4dfYHo5SLZ41K4ASQrjJUaSzl5vvVH0G12G0SiQEAjlV8XPlbnHDEDFbdTO4QIe8ER2/172U1ouLazG0ysDtFFIlSvWX5ZnZUrRMmp/R2aJkzLXEt/zf8Mn4Lfm+itnjgo5R9K4pmPNvvPKNZX5C16lrPT+aA+rd+zXFSmlMg3i5jnxvTdLHhg3G7Q/Uv1ZIJskKt95bzLoe0tUVzRWMYXLIEcohnQg==', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1601574333107'}}, 'updateDate': {'$date': {'$numberLong': '1601574333107'}}, 'status': {'$numberInt': '0'}, 'masterKey': {'provider': 'gcp', 'projectId': 'devprod-drivers', 'location': 'global', 'keyRing': 'key-ring-csfle', 'keyName': 'key-name-csfle'}, 'keyAltNames': ['altname', 'gcp_altname']}] tests: diff --git a/test/spec/client-side-encryption/tests/kmipKMS.json b/test/spec/client-side-encryption/tests/kmipKMS.json new file mode 100644 index 00000000000..5749d21ab81 --- /dev/null +++ b/test/spec/client-side-encryption/tests/kmipKMS.json @@ -0,0 +1,223 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_string_aws": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_azure": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZURE+AAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_gcp": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCP+AAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_local": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_kmip": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "dBHpr8aITfeBQ15grpbLpQ==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "dBHpr8aITfeBQ15grpbLpQ==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "eUYDyB0HuWb+lQgUwO+6qJQyTTDTY2gp9FbemL7ZFo0pvr0x6rm6Ff9OVUTGH6HyMKipaeHdiIJU1dzsLwvqKvi7Beh+U4iaIWX/K0oEg1GOsJc0+Z/in8gNHbGUYLmycHViM3LES3kdt7FdFSUl5rEBHrM71yoNEXImz17QJWMGOuT4x6yoi2pvnaRJwfrI4DjpmnnTrDMac92jgZehbg==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1634220190041" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1634220190041" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "kmip", + "keyId": "1" + }, + "keyAltNames": [ + "altname", + "kmip_altname" + ] + } + ], + "tests": [ + { + "description": "Insert a document with auto encryption using KMIP KMS provider", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "kmip": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string_kmip": "string0" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "dBHpr8aITfeBQ15grpbLpQ==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string_kmip": { + "$binary": { + "base64": "AXQR6a/GiE33gUNeYK6Wy6UCKCwtKFIsL8eKObDVxvqGupJNUk7kXswHhB7G5j/C1D+6no+Asra0KgSU43bTL3ooIBLVyIzbV5CDJYqzAsa4WQ==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string_kmip": { + "$binary": { + "base64": "AXQR6a/GiE33gUNeYK6Wy6UCKCwtKFIsL8eKObDVxvqGupJNUk7kXswHhB7G5j/C1D+6no+Asra0KgSU43bTL3ooIBLVyIzbV5CDJYqzAsa4WQ==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/test/spec/client-side-encryption/tests/kmipKMS.yml b/test/spec/client-side-encryption/tests/kmipKMS.yml new file mode 100644 index 00000000000..874a92bf3bb --- /dev/null +++ b/test/spec/client-side-encryption/tests/kmipKMS.yml @@ -0,0 +1,46 @@ +runOn: + - minServerVersion: "4.1.10" +database_name: &database_name "default" +collection_name: &collection_name "default" + +data: [] +json_schema: {'properties': {'encrypted_string_aws': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_azure': {'encrypt': {'keyId': [{'$binary': {'base64': 'AZURE+AAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_gcp': {'encrypt': {'keyId': [{'$binary': {'base64': 'GCP+AAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_local': {'encrypt': {'keyId': [{'$binary': {'base64': 'AAAAAAAAAAAAAAAAAAAAAA==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}, 'encrypted_string_kmip': {'encrypt': {'keyId': [{'$binary': {'base64': 'dBHpr8aITfeBQ15grpbLpQ==', 'subType': '04'}}], 'bsonType': 'string', 'algorithm': 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic'}}}, 'bsonType': 'object'} +key_vault_data: [{'_id': {'$binary': {'base64': 'dBHpr8aITfeBQ15grpbLpQ==', 'subType': '04'}}, 'keyMaterial': {'$binary': {'base64': 'eUYDyB0HuWb+lQgUwO+6qJQyTTDTY2gp9FbemL7ZFo0pvr0x6rm6Ff9OVUTGH6HyMKipaeHdiIJU1dzsLwvqKvi7Beh+U4iaIWX/K0oEg1GOsJc0+Z/in8gNHbGUYLmycHViM3LES3kdt7FdFSUl5rEBHrM71yoNEXImz17QJWMGOuT4x6yoi2pvnaRJwfrI4DjpmnnTrDMac92jgZehbg==', 'subType': '00'}}, 'creationDate': {'$date': {'$numberLong': '1634220190041'}}, 'updateDate': {'$date': {'$numberLong': '1634220190041'}}, 'status': {'$numberInt': '0'}, 'masterKey': {'provider': 'kmip', 'keyId': '1'}, 'keyAltNames': ['altname', 'kmip_altname']}] + +tests: + - description: "Insert a document with auto encryption using KMIP KMS provider" + clientOptions: + autoEncryptOpts: + kmsProviders: + kmip: {} + operations: + - name: insertOne + arguments: + document: &doc0 { _id: 1, encrypted_string_kmip: "string0" } + expectations: + # Auto encryption will request the collection info. + - command_started_event: + command: + listCollections: 1 + filter: + name: *collection_name + command_name: listCollections + # Then key is fetched from the key vault. + - command_started_event: + command: + find: datakeys + filter: { $or: [ { _id: { $in: [ {'$binary': {'base64': 'dBHpr8aITfeBQ15grpbLpQ==', 'subType': '04'}} ] } }, { keyAltNames: { $in: [] } } ] } + $db: keyvault + command_name: find + - command_started_event: + command: + insert: *collection_name + documents: + - &doc0_encrypted { _id: 1, encrypted_string_kmip: {'$binary': {'base64': 'AXQR6a/GiE33gUNeYK6Wy6UCKCwtKFIsL8eKObDVxvqGupJNUk7kXswHhB7G5j/C1D+6no+Asra0KgSU43bTL3ooIBLVyIzbV5CDJYqzAsa4WQ==', 'subType': '06'}} } + ordered: true + command_name: insert + outcome: + collection: + # Outcome is checked using a separate MongoClient without auto encryption. + data: + - *doc0_encrypted \ No newline at end of file From fe251b116f2d3af708634ae10d39f461f6462dfa Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 20 Dec 2021 12:59:16 +0100 Subject: [PATCH 02/73] test(NODE-3777): setup custom kmip server --- .evergreen/config.yml | 12 ++++++++++++ .evergreen/config.yml.in | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 2744ff3ab9c..4c9fbc79901 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -658,6 +658,18 @@ functions: export CSFLE_GIT_REF="${CSFLE_GIT_REF}" export CDRIVER_GIT_REF="${CDRIVER_GIT_REF}" EOT + - command: shell.exec + params: + script: | + ${PREPARE_SHELL} + cd ${DRIVERS_TOOLS}/.evergreen/csfle + . ./activate_venv.sh + - command: shell.exec + params: + background: true + script: | + cd ${DRIVERS_TOOLS}/.evergreen/csfle + ./kmstlsvenv/bin/python3 -u kms_kmip_server.py - command: shell.exec type: test params: diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index 5c22fed5e07..e1c63ab86f5 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -687,6 +687,18 @@ functions: export CSFLE_GIT_REF="${CSFLE_GIT_REF}" export CDRIVER_GIT_REF="${CDRIVER_GIT_REF}" EOT + - command: shell.exec + params: + script: | + ${PREPARE_SHELL} + cd ${DRIVERS_TOOLS}/.evergreen/csfle + . ./activate_venv.sh + - command: shell.exec + params: + background: true + script: | + cd ${DRIVERS_TOOLS}/.evergreen/csfle + ./kmstlsvenv/bin/python3 -u kms_kmip_server.py - command: shell.exec type: test params: From 3bc3be11271ee290d441fb8f75e458ab9f74f3c3 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 20 Dec 2021 14:01:30 +0100 Subject: [PATCH 03/73] test(NODE-3777): update csfle corpus runner --- .../client_side_encryption.corpus.spec.test.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js index 85517d33c0c..1a7be681ede 100644 --- a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js @@ -55,6 +55,7 @@ describe('Client Side Encryption Corpus', function () { const corpusKeyLocal = loadCorpusData('corpus-key-local.json'); const corpusKeyAws = loadCorpusData('corpus-key-aws.json'); const corpusKeyAzure = loadCorpusData('corpus-key-azure.json'); + const corpusKeyKmip = loadCorpusData('corpus-key-kmip.json'); const corpusKeyGcp = loadCorpusData('corpus-key-gcp.json'); const corpusAll = filterImportedObject(loadCorpusData('corpus.json')); const corpusEncryptedExpectedAll = filterImportedObject(loadCorpusData('corpus-encrypted.json')); @@ -74,20 +75,23 @@ describe('Client Side Encryption Corpus', function () { ['local', corpusKeyLocal._id], ['aws', corpusKeyAws._id], ['azure', corpusKeyAzure._id], - ['gcp', corpusKeyGcp._id] + ['gcp', corpusKeyGcp._id], + ['kmip', corpusKeyKmip._id] ]); const keyAltNameMap = new Map([ ['local', 'local'], ['aws', 'aws'], ['azure', 'azure'], - ['gcp', 'gcp'] + ['gcp', 'gcp'], + ['kmip', 'kmip'] ]); const copyOverValues = new Set([ '_id', 'altname_aws', 'altname_local', 'altname_azure', - 'altname_gcp' + 'altname_gcp', + 'altname_kmip' ]); let client; From 3cb201112978cad85013f78dc18b79f96098566c Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 21 Dec 2021 13:23:23 +0100 Subject: [PATCH 04/73] test(NODE-3777): use csfle beta 1 --- .evergreen/run-tests.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 771a2a427ff..ed8ce6a9b88 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -41,9 +41,7 @@ if [[ -z "${CLIENT_ENCRYPTION}" ]]; then unset AWS_ACCESS_KEY_ID; unset AWS_SECRET_ACCESS_KEY; else - if [[ ! -d ${PROJECT_DIRECTORY}/node_modules/mongodb-client-encryption ]]; then - npm install mongodb-client-encryption@">=2.0.0-beta.0" - fi + npm install mongodb-client-encryption@">=2.0.0-beta.1" pip install --upgrade boto3 # Get access to the AWS temporary credentials: From 7c0cb723d482db9c5c847ff69556400a6791d017 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 21 Dec 2021 14:55:39 +0100 Subject: [PATCH 05/73] test(NODE-3777): ensure kmip key is inserted --- .../client_side_encryption.corpus.spec.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js index 1a7be681ede..6e1ceeef37b 100644 --- a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js @@ -157,7 +157,7 @@ describe('Client Side Encryption Corpus', function () { .catch(() => {}) .then(() => keyDb.collection(keyVaultCollName)) .then(keyColl => - keyColl.insertMany([corpusKeyLocal, corpusKeyAws, corpusKeyAzure, corpusKeyGcp]) + keyColl.insertMany([corpusKeyLocal, corpusKeyAws, corpusKeyAzure, corpusKeyGcp, corpusKeyKmip]) ); }); }); From baaa7b3f327aacd348793b3947f597701c692152 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 22 Dec 2021 13:21:43 +0100 Subject: [PATCH 06/73] test(NODE-3777): use csfle beta 2 --- .evergreen/run-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index ed8ce6a9b88..c7d3667416e 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -41,7 +41,7 @@ if [[ -z "${CLIENT_ENCRYPTION}" ]]; then unset AWS_ACCESS_KEY_ID; unset AWS_SECRET_ACCESS_KEY; else - npm install mongodb-client-encryption@">=2.0.0-beta.1" + npm install mongodb-client-encryption@">=2.0.0-beta.2" pip install --upgrade boto3 # Get access to the AWS temporary credentials: From f42fceb74180c4bac0a9998176b51952967ab536 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 5 Jan 2022 21:02:45 +0100 Subject: [PATCH 07/73] test(NODE-3777): properly setup kmip in runner --- .../client_side_encryption.corpus.spec.test.js | 3 +++ test/tools/runner/config.ts | 5 +++++ test/tools/spec-runner/index.js | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js index 6e1ceeef37b..d80a6336199 100644 --- a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js @@ -29,6 +29,9 @@ describe('Client Side Encryption Corpus', function () { 'base64' ) }; + kmsProviders.kmip = { + endpoint: 'localhost:5698' + }; // TODO: build this into EJSON // TODO: make a custom chai assertion for this diff --git a/test/tools/runner/config.ts b/test/tools/runner/config.ts index 3052f5b4c34..cd058b3858e 100644 --- a/test/tools/runner/config.ts +++ b/test/tools/runner/config.ts @@ -370,6 +370,11 @@ export class TestConfiguration { key: localKey }; } + if (typeof type !== 'string' || type === 'kmip') { + kmsProviders.kmip = { + endpoint: 'localhost:5698' + }; + } return kmsProviders; } } diff --git a/test/tools/spec-runner/index.js b/test/tools/spec-runner/index.js index 7e484d402b8..e7be5d42644 100644 --- a/test/tools/spec-runner/index.js +++ b/test/tools/spec-runner/index.js @@ -71,6 +71,12 @@ function translateClientOptions(options) { }; } + if (options.autoEncryptOpts.kmsProviders.kmip) { + kmsProviders.kmip = { + endpoint: 'localhost:5698' + }; + } + options.autoEncryption.kmsProviders = kmsProviders; } From 6790cab2df1726cd205c707b66b36b0da37804b1 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 17 Jan 2022 21:19:31 +0100 Subject: [PATCH 08/73] feat(NODE-3777): pass tls options through to csfle --- src/deps.ts | 30 +++++++++++++++++++ ...client_side_encryption.corpus.spec.test.js | 12 ++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/deps.ts b/src/deps.ts index 9d6fa769fbb..dd447a8d9c7 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -174,6 +174,28 @@ export const AutoEncryptionLoggerLevel = Object.freeze({ export type AutoEncryptionLoggerLevel = typeof AutoEncryptionLoggerLevel[keyof typeof AutoEncryptionLoggerLevel]; +/** @public */ +export interface AutoEncryptionTlsOptions { + /** + * Specifies the location of a local .pem file that contains + * either the client's TLS/SSL certificate and key or only the + * client's TLS/SSL key when tlsCertificateFile is used to + * provide the certificate. + */ + tlsCertificateKeyFile?: string; + /** + * Specifies the password to de-crypt the tlsCertificateKeyFile. + */ + tlsCertificateKeyFilePassword?: string; + /** + * Specifies the location of a local .pem file that contains the + * root certificate chain from the Certificate Authority. + * This file is used to validate the certificate presented by the + * KMS provider. + */ + tlsCAFile?: string; +} + /** @public */ export interface AutoEncryptionOptions { /** @internal */ @@ -275,6 +297,14 @@ export interface AutoEncryptionOptions { mongocryptdSpawnArgs?: string[]; }; proxyOptions?: ProxyOptions; + /** The TLS options to use connecting to the KMS provider */ + tlsOptions?: { + aws?: AutoEncryptionTlsOptions; + local?: AutoEncryptionTlsOptions; + azure?: AutoEncryptionTlsOptions; + gcp?: AutoEncryptionTlsOptions; + kmip?: AutoEncryptionTlsOptions; + } } /** @public */ diff --git a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js index d80a6336199..9e692382495 100644 --- a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js @@ -202,9 +202,16 @@ describe('Client Side Encryption Corpus', function () { // .. code:: javascript // Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk // Configure both objects with ``keyVaultNamespace`` set to ``keyvault.datakeys``. + const tlsOptions = { + kmip: { + tlsCAFile: '/Users/modetojoy/work/mongodb-labs/drivers-evergreen-tools/.evergreen/x509gen/ca.pem', + tlsCertificateKeyFile: '/Users/modetojoy/work/mongodb-labs/drivers-evergreen-tools/.evergreen/x509gen/client.pem' + } + }; const autoEncryption = { keyVaultNamespace, - kmsProviders + kmsProviders, + tlsOptions }; if (useClientSideSchema) { autoEncryption.schemaMap = { @@ -217,7 +224,8 @@ describe('Client Side Encryption Corpus', function () { clientEncryption = new mongodbClientEncryption.ClientEncryption(client, { bson: BSON, keyVaultNamespace, - kmsProviders + kmsProviders, + tlsOptions }); }); }); From c59415c92499be43095e7c99ca0a61544d9572db Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 17 Jan 2022 21:43:22 +0100 Subject: [PATCH 09/73] test(NODE-377): use env var for kmip certs --- .../client_side_encryption.corpus.spec.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js index 9e692382495..66afbde9045 100644 --- a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js @@ -204,8 +204,8 @@ describe('Client Side Encryption Corpus', function () { // Configure both objects with ``keyVaultNamespace`` set to ``keyvault.datakeys``. const tlsOptions = { kmip: { - tlsCAFile: '/Users/modetojoy/work/mongodb-labs/drivers-evergreen-tools/.evergreen/x509gen/ca.pem', - tlsCertificateKeyFile: '/Users/modetojoy/work/mongodb-labs/drivers-evergreen-tools/.evergreen/x509gen/client.pem' + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE } }; const autoEncryption = { From a0e9c31e6350895b6e2a80653fd88a068c0b0a91 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 17 Jan 2022 21:48:54 +0100 Subject: [PATCH 10/73] test(NODE-3777): adding env vars to evg --- .evergreen/run-custom-csfle-tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.evergreen/run-custom-csfle-tests.sh b/.evergreen/run-custom-csfle-tests.sh index 7ef02df7550..5a4296c4e82 100644 --- a/.evergreen/run-custom-csfle-tests.sh +++ b/.evergreen/run-custom-csfle-tests.sh @@ -63,6 +63,8 @@ popd # ../csfle-deps-tmp cp -R ../csfle-deps-tmp/libmongocrypt/bindings/node node_modules/mongodb-client-encryption export MONGODB_URI=${MONGODB_URI} +export KMIP_TLS_CA_FILE="${DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem" +export KMIP_TLS_CERT_FILE="${DRIVERS_TOOLS}/.evergreen/x509gen/client.pem" set +o errexit # We want to run both test suites even if the first fails npm run check:csfle DRIVER_CSFLE_TEST_RESULT=$? From 625d4208d5b7c343e6895c683d39afe261f65d77 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 18 Jan 2022 21:45:43 +0100 Subject: [PATCH 11/73] test(NODE-3777): add more test kmip tls opts --- .../client_side_encryption.prose.test.js | 3 +++ test/tools/spec-runner/index.js | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 64f052b84f7..99b2996ab72 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -12,6 +12,9 @@ const getKmsProviders = localKey => { if (localKey) { result.local = { key: localKey }; } + result.kmip = { + endpoint: 'localhost:5698' + }; return result; }; diff --git a/test/tools/spec-runner/index.js b/test/tools/spec-runner/index.js index e7be5d42644..313f8e0fc49 100644 --- a/test/tools/spec-runner/index.js +++ b/test/tools/spec-runner/index.js @@ -75,6 +75,12 @@ function translateClientOptions(options) { kmsProviders.kmip = { endpoint: 'localhost:5698' }; + options.autoEncryption.tlsOptions = { + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } } options.autoEncryption.kmsProviders = kmsProviders; From 6b45146e6f32014f5d5e2e1426ac42bc4d2e3f96 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 18 Jan 2022 22:59:57 +0100 Subject: [PATCH 12/73] test(NODE-3777): run csfle tests against pr --- .evergreen/run-custom-csfle-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/run-custom-csfle-tests.sh b/.evergreen/run-custom-csfle-tests.sh index 5a4296c4e82..94b1581414a 100644 --- a/.evergreen/run-custom-csfle-tests.sh +++ b/.evergreen/run-custom-csfle-tests.sh @@ -36,7 +36,7 @@ pushd ../csfle-deps-tmp rm -rf libmongocrypt mongo-c-driver -git clone https://github.com/mongodb/libmongocrypt.git +git clone --branch NODE-3777 https://github.com/mongodb/libmongocrypt.git pushd libmongocrypt git fetch --tags git checkout "$CSFLE_GIT_REF" -b csfle-custom From c7ef16bc4a104fbd14ca0208256db42cd190a32d Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 18 Jan 2022 23:25:08 +0100 Subject: [PATCH 13/73] test(NODE-3777): add extra temp scripts for csfle --- .evergreen/run-custom-csfle-tests.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.evergreen/run-custom-csfle-tests.sh b/.evergreen/run-custom-csfle-tests.sh index 94b1581414a..c6b720930cd 100644 --- a/.evergreen/run-custom-csfle-tests.sh +++ b/.evergreen/run-custom-csfle-tests.sh @@ -36,7 +36,7 @@ pushd ../csfle-deps-tmp rm -rf libmongocrypt mongo-c-driver -git clone --branch NODE-3777 https://github.com/mongodb/libmongocrypt.git +git clone https://github.com/mongodb/libmongocrypt.git pushd libmongocrypt git fetch --tags git checkout "$CSFLE_GIT_REF" -b csfle-custom @@ -59,6 +59,15 @@ bash ./etc/build-static.sh popd # libmongocrypt/bindings/node popd # ../csfle-deps-tmp +# This can be removed after libmongocrypt PR merged. +rm -rf ../csfle-deps-tmp/libmongocrypt +pushd ../csfle-deps-tmp +git clone --depth 1 --branch NODE-3777 https://github.com/mongodb/libmongocrypt.git +pushd libmongocrypt/bindings/node +npm install --production --ignore-scripts +popd # libmongocrypt/bindings/node +popd # ../csfle-deps-tmp + # copy mongodb-client-encryption into driver's node_modules cp -R ../csfle-deps-tmp/libmongocrypt/bindings/node node_modules/mongodb-client-encryption From 75fb5c2436487adcbb59088ff66b260ec813d238 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 18 Jan 2022 23:38:08 +0100 Subject: [PATCH 14/73] test(NODE-3777): change custom csfle branch --- .evergreen/run-custom-csfle-tests.sh | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.evergreen/run-custom-csfle-tests.sh b/.evergreen/run-custom-csfle-tests.sh index c6b720930cd..75e82d857ed 100644 --- a/.evergreen/run-custom-csfle-tests.sh +++ b/.evergreen/run-custom-csfle-tests.sh @@ -27,7 +27,7 @@ ABS_PATH_TO_PATCH=$(pwd) # CSFLE_GIT_REF - set the git reference to checkout for a custom CSFLE version # CDRIVER_GIT_REF - set the git reference to checkout for a custom CDRIVER version (this is for libbson) -CSFLE_GIT_REF=${CSFLE_GIT_REF:-master} +CSFLE_GIT_REF=${CSFLE_GIT_REF:-NODE-3777} CDRIVER_GIT_REF=${CDRIVER_GIT_REF:-1.17.6} rm -rf ../csfle-deps-tmp @@ -59,15 +59,6 @@ bash ./etc/build-static.sh popd # libmongocrypt/bindings/node popd # ../csfle-deps-tmp -# This can be removed after libmongocrypt PR merged. -rm -rf ../csfle-deps-tmp/libmongocrypt -pushd ../csfle-deps-tmp -git clone --depth 1 --branch NODE-3777 https://github.com/mongodb/libmongocrypt.git -pushd libmongocrypt/bindings/node -npm install --production --ignore-scripts -popd # libmongocrypt/bindings/node -popd # ../csfle-deps-tmp - # copy mongodb-client-encryption into driver's node_modules cp -R ../csfle-deps-tmp/libmongocrypt/bindings/node node_modules/mongodb-client-encryption From 04f96a481b9fbf07710201d02f24ea7fdeeac62e Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 19 Jan 2022 00:13:48 +0100 Subject: [PATCH 15/73] test(NODE-3777): use git ref for custom branch --- .evergreen/run-custom-csfle-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/run-custom-csfle-tests.sh b/.evergreen/run-custom-csfle-tests.sh index 75e82d857ed..f02c79cde22 100644 --- a/.evergreen/run-custom-csfle-tests.sh +++ b/.evergreen/run-custom-csfle-tests.sh @@ -27,7 +27,7 @@ ABS_PATH_TO_PATCH=$(pwd) # CSFLE_GIT_REF - set the git reference to checkout for a custom CSFLE version # CDRIVER_GIT_REF - set the git reference to checkout for a custom CDRIVER version (this is for libbson) -CSFLE_GIT_REF=${CSFLE_GIT_REF:-NODE-3777} +CSFLE_GIT_REF=${CSFLE_GIT_REF:-51fb6d6e4448fba9d6638dc4483062eceb5f1b75} CDRIVER_GIT_REF=${CDRIVER_GIT_REF:-1.17.6} rm -rf ../csfle-deps-tmp From b84a709db600fc59e08ba8c11bbae8879aaf438c Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 19 Jan 2022 00:55:13 +0100 Subject: [PATCH 16/73] test(NODE-3777): no run against legacy csfle --- .evergreen/run-custom-csfle-tests.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.evergreen/run-custom-csfle-tests.sh b/.evergreen/run-custom-csfle-tests.sh index f02c79cde22..0389db4f99d 100644 --- a/.evergreen/run-custom-csfle-tests.sh +++ b/.evergreen/run-custom-csfle-tests.sh @@ -106,7 +106,8 @@ if [ $DRIVER_CSFLE_TEST_RESULT -ne 0 ]; then exit 1 fi -echo "Test legacy version of FLE bindings" -rm -rf node_modules/mongodb-client-encryption -npm install mongodb-client-encryption@"^1.2.7" -npm run check:csfle +# These will now obviously fail as KMIP doesn't exist in the old bindings. +# echo "Test legacy version of FLE bindings" +# rm -rf node_modules/mongodb-client-encryption +# npm install mongodb-client-encryption@"^1.2.7" +# npm run check:csfle From 1c5545a9ec1a980d99c9d7cfd2b6ba757a73efaf Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 19 Jan 2022 01:32:14 +0100 Subject: [PATCH 17/73] fix(NODE-3777): fix ts and lint errors --- src/deps.ts | 2 +- src/index.ts | 2 +- .../client_side_encryption.corpus.spec.test.js | 8 +++++++- test/tools/spec-runner/index.js | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/deps.ts b/src/deps.ts index dd447a8d9c7..7b193a9d28c 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -304,7 +304,7 @@ export interface AutoEncryptionOptions { azure?: AutoEncryptionTlsOptions; gcp?: AutoEncryptionTlsOptions; kmip?: AutoEncryptionTlsOptions; - } + }; } /** @public */ diff --git a/src/index.ts b/src/index.ts index eb7cc75f971..4a82c1bcbda 100644 --- a/src/index.ts +++ b/src/index.ts @@ -229,7 +229,7 @@ export type { export type { InternalAbstractCursorOptions } from './cursor/abstract_cursor'; export type { AggregationCursorOptions } from './cursor/aggregation_cursor'; export type { DbOptions, DbPrivate } from './db'; -export type { AutoEncrypter, AutoEncryptionOptions } from './deps'; +export type { AutoEncrypter, AutoEncryptionOptions, AutoEncryptionTlsOptions } from './deps'; export type { Encrypter, EncrypterOptions } from './encrypter'; export type { AnyError, ErrorDescription, MongoNetworkErrorOptions } from './error'; export type { Explain, ExplainOptions, ExplainVerbosityLike } from './explain'; diff --git a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js index 66afbde9045..c01f3d71431 100644 --- a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js @@ -160,7 +160,13 @@ describe('Client Side Encryption Corpus', function () { .catch(() => {}) .then(() => keyDb.collection(keyVaultCollName)) .then(keyColl => - keyColl.insertMany([corpusKeyLocal, corpusKeyAws, corpusKeyAzure, corpusKeyGcp, corpusKeyKmip]) + keyColl.insertMany([ + corpusKeyLocal, + corpusKeyAws, + corpusKeyAzure, + corpusKeyGcp, + corpusKeyKmip + ]) ); }); }); diff --git a/test/tools/spec-runner/index.js b/test/tools/spec-runner/index.js index 313f8e0fc49..0cbac9ff69c 100644 --- a/test/tools/spec-runner/index.js +++ b/test/tools/spec-runner/index.js @@ -80,7 +80,7 @@ function translateClientOptions(options) { tlsCAFile: process.env.KMIP_TLS_CA_FILE, tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE } - } + }; } options.autoEncryption.kmsProviders = kmsProviders; From 7c48c6b074fcc94692f3e9ac3492cec60738356f Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 19 Jan 2022 15:06:22 +0100 Subject: [PATCH 18/73] feat(NODE-3777): setup kmip server for prose tests --- .evergreen/config.yml | 14 ++++++++++++-- .evergreen/config.yml.in | 5 ++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 4c9fbc79901..fa675834113 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -667,9 +667,19 @@ functions: - command: shell.exec params: background: true - script: | + script: > cd ${DRIVERS_TOOLS}/.evergreen/csfle - ./kmstlsvenv/bin/python3 -u kms_kmip_server.py + + ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & + + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem + --port 8000 & + + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file + ../x509gen/wrong-host.pem --port 8001 & + + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem + --port 8002 --require_client_cert & - command: shell.exec type: test params: diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index e1c63ab86f5..99d8ffe5dcb 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -698,7 +698,10 @@ functions: background: true script: | cd ${DRIVERS_TOOLS}/.evergreen/csfle - ./kmstlsvenv/bin/python3 -u kms_kmip_server.py + ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & - command: shell.exec type: test params: From 92df33ab61de719c3649eed9c2ddf4c64ba32b92 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 19 Jan 2022 15:34:25 +0100 Subject: [PATCH 19/73] test(NODE-3777): prose test outline --- .../client_side_encryption.prose.test.js | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 99b2996ab72..eaa4406e362 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -209,6 +209,124 @@ describe('Client Side Encryption Prose Tests', function () { }); }); + context('when kmip is the kms provider', metadata, function () { + context('when encrypting with kmip', function () { + /** + * 10. + * - Create data key with kmip as provider and master key of { keyId: '1' } + * - Use UUID to encrypt and decrypt to value. + * - Create data key with invalid encrypter and expect failure. + */ + it('must create a data key', function () { + + }); + + it('properly encrypts and decrypts', function () { + + }); + + it('fails with invalid provider host', function () { + + }); + + /** + * 11. + * - Create data key with kmip as provider and master key of + * { keyId: 1, endpoint: 'localhost:5698 '} + * - Use UUID to encrypt and decrypt to value. + */ + it('must create a data key', function () { + + }); + + it('properly encrypts and decrypts', function () { + + }); + + /** + * 12. + * - Create data key with kmip as provider and master key of + * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} + * - Expect failure. + */ + it('fails with invalid provider host', function () { + + }); + }); + }); + + /** + * - Create client encryption no tls + * - Create client encryption with tls + * - Create client encryption expired + * - Create client encryption invalid hostname + */ + context('when passing through tls options', metadata, function () { + // Case 1. + context('when using aws', function () { + it('must create data keys', function () { + + }); + + it('fails with expired certificates', function () { + + }); + + it('fails with invalid hostnames', function () { + + }); + }); + + // Case 2. + context('when using azure', function () { + it('must create data keys', function () { + + }); + + it('fails with expired certificates', function () { + + }); + + it('fails with invalid hostnames', function () { + + }); + }); + + // Case 3. + context('when using gcp', function () { + it('must create data keys', function () { + + }); + + it('fails with expired certificates', function () { + + }); + + it('fails with invalid hostnames', function () { + + }); + }); + + // Case 4. + context('when using kmip', function () { + it('fails without endpoint', function () { + + }); + + it('must create data keys', function () { + + }); + + it('fails with expired certificates', function () { + + }); + + it('fails with invalid hostnames', function () { + + }); + }); + }); + it('should work for aws KMS provider', metadata, function () { // Then, repeat the above tests with the ``aws`` KMS provider: let awsDatakeyId; From 5d3705a3ced09473e8572582ff2821bd1f085d59 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 20 Jan 2022 16:57:42 +0100 Subject: [PATCH 20/73] test(NODE-3777): first batch prose tests --- .../client_side_encryption.prose.test.js | 147 ++++++++++++++---- 1 file changed, 117 insertions(+), 30 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index eaa4406e362..b1946e913a3 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -210,48 +210,135 @@ describe('Client Side Encryption Prose Tests', function () { }); context('when kmip is the kms provider', metadata, function () { - context('when encrypting with kmip', function () { - /** - * 10. - * - Create data key with kmip as provider and master key of { keyId: '1' } - * - Use UUID to encrypt and decrypt to value. - * - Create data key with invalid encrypter and expect failure. - */ - it('must create a data key', function () { - + before(async function () { + this.client = this.configuration.newClient(); + await this.client.connect(); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { + bson: BSON, + keyVaultNamespace, + kmsProviders: { + kmip: { + endpoint: 'localhost:5698' + } + }, + tlsOptions: { + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } }); - - it('properly encrypts and decrypts', function () { - + this.clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(this.client, { + bson: BSON, + keyVaultNamespace, + kmsProviders: { + kmip: { + endpoint: 'invalid.localhost:5698' + } + }, + tlsOptions: { + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } }); + }); - it('fails with invalid provider host', function () { + after(async function () { + await this.client.close(); + }); - }); + context('when encrypting with kmip', function () { + context('when not providing an endpoint in the master key', function () { + const masterKey = { keyId: '1' }; + let dataKey; + let encrypted; + let decrypted; + + /** + * 10. + * - Create data key with kmip as provider and master key of { keyId: '1' } + * - Use UUID to encrypt and decrypt to value. + * - Create data key with invalid encrypter and expect failure. + */ + before(async function () { + dataKey = await this.clientEncryption.createDataKey('kmip', { masterKey }); + encrypted = await this.clientEncryption.encrypt('test', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: dataKey + }); + decrypted = await this.clientEncryption.decrypt(encrypted); + }); - /** - * 11. - * - Create data key with kmip as provider and master key of - * { keyId: 1, endpoint: 'localhost:5698 '} - * - Use UUID to encrypt and decrypt to value. - */ - it('must create a data key', function () { + it('must create a data key', function () { + expect(dataKey).to.have.property('sub_type', 4); + }); + it('properly encrypts and decrypts', function () { + expect(decrypted).to.equal('test'); + }); + + it('fails with invalid provider host', async function () { + try { + await this.clientEncryptionInvalid.createDataKey('kmip', { masterKey }); + } catch (e) { + expect(e.message).to.equal('KMS request failed'); + } + }); }); - it('properly encrypts and decrypts', function () { + context('when providing an endpoint in the master key', function () { + context('when the endpoint is valid', function () { + const masterKey = { keyId: '1', endpoint: 'localhost:5698' }; + let dataKey; + let encrypted; + let decrypted; + + /** + * 11. + * - Create data key with kmip as provider and master key of + * { keyId: 1, endpoint: 'localhost:5698 '} + * - Use UUID to encrypt and decrypt to value. + */ + before(async function () { + dataKey = await this.clientEncryption.createDataKey('kmip', { masterKey }); + encrypted = await this.clientEncryption.encrypt('test', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: dataKey + }); + decrypted = await this.clientEncryption.decrypt(encrypted); + }); - }); + it('must create a data key', function () { + expect(dataKey).to.have.property('sub_type', 4); + }); - /** - * 12. - * - Create data key with kmip as provider and master key of - * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} - * - Expect failure. - */ - it('fails with invalid provider host', function () { + it('properly encrypts and decrypts', function () { + expect(decrypted).to.equal('test'); + }); + }); + context('when the endpoint is invalid', function () { + const masterKey = { keyId: '1', endpoint: 'doesnotexist.localhost:5698' }; + + /** + * 12. + * - Create data key with kmip as provider and master key of + * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} + * - Expect failure. + */ + it('fails with invalid provider host', async function () { + try { + await this.clientEncryptionInvalid.createDataKey('kmip', { masterKey }); + } catch (e) { + expect(e.message).to.equal('KMS request failed'); + } + }); + }); }); + }); }); From 774dc3466c1a366da745b9c007fcfc2220b576ca Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 20 Jan 2022 22:52:27 +0100 Subject: [PATCH 21/73] test(NODE-3777): remaining test setup for prose tests --- .../client_side_encryption.prose.test.js | 157 +++++++++++++----- 1 file changed, 120 insertions(+), 37 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index b1946e913a3..9985cf90552 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -7,15 +7,23 @@ const expect = chai.expect; chai.use(require('chai-subset')); const { LEGACY_HELLO_COMMAND } = require('../../../src/constants'); -const getKmsProviders = localKey => { +const getKmsProviders = (localKey, kmipEndpoint, azureEndpoint, gcpEndpoint) => { const result = BSON.EJSON.parse(process.env.CSFLE_KMS_PROVIDERS || 'NOT_PROVIDED'); if (localKey) { result.local = { key: localKey }; } result.kmip = { - endpoint: 'localhost:5698' + endpoint: kmipEndpoint || 'localhost:5698' }; + if (result.azure && azureEndpoint) { + result.azure.endpoint = azureEndpoint; + } + + if (result.gcp && gcpEndpoint) { + result.gcp.endpoint = gcpEndpoint; + } + return result; }; @@ -209,45 +217,46 @@ describe('Client Side Encryption Prose Tests', function () { }); }); - context('when kmip is the kms provider', metadata, function () { + context.only('when kmip is the kms provider', metadata, function () { + const autoEncryptionOptions = { + keyVaultNamespace, + kmsProviders: { + kmip: { + endpoint: 'localhost:5698' + } + }, + tlsOptions: { + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } + }; + let client; + let clientEncryption; + let clientEncryptionInvalid; + before(async function () { - this.client = this.configuration.newClient(); - await this.client.connect(); + client = this.configuration.newClient(); + await client.connect(); const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { - bson: BSON, - keyVaultNamespace, - kmsProviders: { - kmip: { - endpoint: 'localhost:5698' - } - }, - tlsOptions: { - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - } - } + clientEncryption = new mongodbClientEncryption.ClientEncryption(client, { + ...autoEncryptionOptions, + bson: BSON }); - this.clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(this.client, { + clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(client, { + ...autoEncryptionOptions, bson: BSON, - keyVaultNamespace, kmsProviders: { kmip: { endpoint: 'invalid.localhost:5698' } - }, - tlsOptions: { - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - } } }); }); after(async function () { - await this.client.close(); + await client.close(true); }); context('when encrypting with kmip', function () { @@ -264,12 +273,12 @@ describe('Client Side Encryption Prose Tests', function () { * - Create data key with invalid encrypter and expect failure. */ before(async function () { - dataKey = await this.clientEncryption.createDataKey('kmip', { masterKey }); - encrypted = await this.clientEncryption.encrypt('test', { + dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); + encrypted = await clientEncryption.encrypt('test', { algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', keyId: dataKey }); - decrypted = await this.clientEncryption.decrypt(encrypted); + decrypted = await clientEncryption.decrypt(encrypted); }); it('must create a data key', function () { @@ -280,9 +289,9 @@ describe('Client Side Encryption Prose Tests', function () { expect(decrypted).to.equal('test'); }); - it('fails with invalid provider host', async function () { + it.only('fails with invalid provider host', async function () { try { - await this.clientEncryptionInvalid.createDataKey('kmip', { masterKey }); + await clientEncryptionInvalid.createDataKey('kmip', { masterKey }); } catch (e) { expect(e.message).to.equal('KMS request failed'); } @@ -303,12 +312,12 @@ describe('Client Side Encryption Prose Tests', function () { * - Use UUID to encrypt and decrypt to value. */ before(async function () { - dataKey = await this.clientEncryption.createDataKey('kmip', { masterKey }); - encrypted = await this.clientEncryption.encrypt('test', { + dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); + encrypted = await clientEncryption.encrypt('test', { algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', keyId: dataKey }); - decrypted = await this.clientEncryption.decrypt(encrypted); + decrypted = await clientEncryption.decrypt(encrypted); }); it('must create a data key', function () { @@ -331,7 +340,7 @@ describe('Client Side Encryption Prose Tests', function () { */ it('fails with invalid provider host', async function () { try { - await this.clientEncryptionInvalid.createDataKey('kmip', { masterKey }); + await clientEncryption.createDataKey('kmip', { masterKey }); } catch (e) { expect(e.message).to.equal('KMS request failed'); } @@ -349,6 +358,80 @@ describe('Client Side Encryption Prose Tests', function () { * - Create client encryption invalid hostname */ context('when passing through tls options', metadata, function () { + const tlsCaOptions = { + aws: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + azure: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + gcp: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + } + } + const clientNoTlsOptions = { + kmsProviders: getKmsProviders() + }; + const clientWithTlsOptions = { + kmsProviders: getKmsProviders(), + tlsOptions: { + aws: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + azure: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + gcp: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } + }; + const clientWithTlsExpiredOptions = { + kmsProviders: getKmsProviders('127.0.0.1:8000', '127.0.0.1:8000', '127.0.0.1:8000'), + tlsOptions: tlsCaOptions + }; + const clientWithInvalidHostnameOptions = { + kmsProviders: getKmsProviders('127.0.0.1:8001', '127.0.0.1:8001', '127.0.0.1:8001'), + tlsOptions: tlsCaOptions + }; + + let clientNoTls; + let clientWithTls; + let clientWithTlsExpired; + let clientWithInvalidHostname; + + beforeEach(async function () { + clientNoTls = this.configuration.newClient({}, { + autoEncryption: clientNoTlsOptions + }); + clientWithTls = this.configuration.newClient({}, { + autoEncryption: clientWithTlsOptions + }); + clientWithTlsExpired = this.configuration.newClient({}, { + autoEncryption: clientWithTlsExpiredOptions + }); + clientWithInvalidHostname = this.configuration.newClient({}, { + autoEncryption: clientWithInvalidHostnameOptions + }); + }); + + afterEach(async function () { + await clientNoTls.close(true); + await clientWithTls.close(true); + await clientWithTlsExpired.close(true); + await clientWithInvalidHostname.close(true); + }); + // Case 1. context('when using aws', function () { it('must create data keys', function () { From f930d026b5bf1c2639af87b6ddf4185dd9424d2a Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 24 Jan 2022 07:24:59 +0100 Subject: [PATCH 22/73] fix(NODE-3777): destroy socks5 socket on end --- .../client_side_encryption.prose.test.js | 560 +++++++++--------- 1 file changed, 280 insertions(+), 280 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 9985cf90552..599a437fbe1 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -55,6 +55,286 @@ describe('Client Side Encryption Prose Tests', function () { 'base64' ); + context.only('when kmip is the kms provider', metadata, function () { + const autoEncryptionOptions = { + keyVaultNamespace, + kmsProviders: { + kmip: { + endpoint: 'localhost:5698' + } + }, + tlsOptions: { + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } + }; + let client; + let clientEncryption; + let clientEncryptionInvalid; + + before(async function () { + client = this.configuration.newClient(); + await client.connect(); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + clientEncryption = new mongodbClientEncryption.ClientEncryption(client, { + ...autoEncryptionOptions, + bson: BSON + }); + clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(client, { + ...autoEncryptionOptions, + bson: BSON, + kmsProviders: { + kmip: { + endpoint: 'invalid.localhost:5698' + } + } + }); + }); + + after(async function () { + await client.close(true); + }); + + context.only('when encrypting with kmip', function () { + context('when not providing an endpoint in the master key', function () { + const masterKey = { keyId: '1' }; + let dataKey; + let encrypted; + let decrypted; + + /** + * 10. + * - Create data key with kmip as provider and master key of { keyId: '1' } + * - Use UUID to encrypt and decrypt to value. + * - Create data key with invalid encrypter and expect failure. + */ + before(async function () { + dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); + encrypted = await clientEncryption.encrypt('test', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: dataKey + }); + decrypted = await clientEncryption.decrypt(encrypted); + }); + + it('must create a data key', function () { + expect(dataKey).to.have.property('sub_type', 4); + }); + + it('properly encrypts and decrypts', function () { + expect(decrypted).to.equal('test'); + }); + + it('fails with invalid provider host', async function () { + try { + await clientEncryptionInvalid.createDataKey('kmip', { masterKey }); + } catch (e) { + expect(e.message).to.equal('KMS request failed'); + } + }); + }); + + context('when providing an endpoint in the master key', function () { + context('when the endpoint is valid', function () { + const masterKey = { keyId: '1', endpoint: 'localhost:5698' }; + let dataKey; + let encrypted; + let decrypted; + + /** + * 11. + * - Create data key with kmip as provider and master key of + * { keyId: 1, endpoint: 'localhost:5698 '} + * - Use UUID to encrypt and decrypt to value. + */ + before(async function () { + dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); + encrypted = await clientEncryption.encrypt('test', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: dataKey + }); + decrypted = await clientEncryption.decrypt(encrypted); + }); + + it('must create a data key', function () { + expect(dataKey).to.have.property('sub_type', 4); + }); + + it('properly encrypts and decrypts', function () { + expect(decrypted).to.equal('test'); + }); + }); + + context('when the endpoint is invalid', function () { + const masterKey = { keyId: '1', endpoint: 'doesnotexist.localhost:5698' }; + + /** + * 12. + * - Create data key with kmip as provider and master key of + * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} + * - Expect failure. + */ + it('fails with invalid provider host', async function () { + try { + await clientEncryption.createDataKey('kmip', { masterKey }); + } catch (e) { + expect(e.message).to.equal('KMS request failed'); + } + }); + }); + }); + + }); + }); + + /** + * - Create client encryption no tls + * - Create client encryption with tls + * - Create client encryption expired + * - Create client encryption invalid hostname + */ + context('when passing through tls options', metadata, function () { + const tlsCaOptions = { + aws: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + azure: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + gcp: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + } + } + const clientNoTlsOptions = { + kmsProviders: getKmsProviders() + }; + const clientWithTlsOptions = { + kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), + tlsOptions: { + aws: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + azure: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + gcp: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } + }; + const clientWithTlsExpiredOptions = { + kmsProviders: getKmsProviders(null, '127.0.0.1:8000', '127.0.0.1:8000', '127.0.0.1:8000'), + tlsOptions: tlsCaOptions + }; + const clientWithInvalidHostnameOptions = { + kmsProviders: getKmsProviders(null, '127.0.0.1:8001', '127.0.0.1:8001', '127.0.0.1:8001'), + tlsOptions: tlsCaOptions + }; + + let clientNoTls; + let clientWithTls; + let clientWithTlsExpired; + let clientWithInvalidHostname; + + beforeEach(async function () { + clientNoTls = this.configuration.newClient({}, { + autoEncryption: clientNoTlsOptions + }); + clientWithTls = this.configuration.newClient({}, { + autoEncryption: clientWithTlsOptions + }); + clientWithTlsExpired = this.configuration.newClient({}, { + autoEncryption: clientWithTlsExpiredOptions + }); + clientWithInvalidHostname = this.configuration.newClient({}, { + autoEncryption: clientWithInvalidHostnameOptions + }); + }); + + afterEach(async function () { + await clientNoTls.close(true); + await clientWithTls.close(true); + await clientWithTlsExpired.close(true); + await clientWithInvalidHostname.close(true); + }); + + // Case 1. + context('when using aws', function () { + it('must create data keys', function () { + + }); + + it('fails with expired certificates', function () { + + }); + + it('fails with invalid hostnames', function () { + + }); + }); + + // Case 2. + context('when using azure', function () { + it('must create data keys', function () { + + }); + + it('fails with expired certificates', function () { + + }); + + it('fails with invalid hostnames', function () { + + }); + }); + + // Case 3. + context('when using gcp', function () { + it('must create data keys', function () { + + }); + + it('fails with expired certificates', function () { + + }); + + it('fails with invalid hostnames', function () { + + }); + }); + + // Case 4. + context('when using kmip', function () { + it('fails without endpoint', function () { + + }); + + it('must create data keys', function () { + + }); + + it('fails with expired certificates', function () { + + }); + + it('fails with invalid hostnames', function () { + + }); + }); + }); + describe('Data key and double encryption', function () { // Data key and double encryption // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -217,286 +497,6 @@ describe('Client Side Encryption Prose Tests', function () { }); }); - context.only('when kmip is the kms provider', metadata, function () { - const autoEncryptionOptions = { - keyVaultNamespace, - kmsProviders: { - kmip: { - endpoint: 'localhost:5698' - } - }, - tlsOptions: { - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - } - } - }; - let client; - let clientEncryption; - let clientEncryptionInvalid; - - before(async function () { - client = this.configuration.newClient(); - await client.connect(); - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - clientEncryption = new mongodbClientEncryption.ClientEncryption(client, { - ...autoEncryptionOptions, - bson: BSON - }); - clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(client, { - ...autoEncryptionOptions, - bson: BSON, - kmsProviders: { - kmip: { - endpoint: 'invalid.localhost:5698' - } - } - }); - }); - - after(async function () { - await client.close(true); - }); - - context('when encrypting with kmip', function () { - context('when not providing an endpoint in the master key', function () { - const masterKey = { keyId: '1' }; - let dataKey; - let encrypted; - let decrypted; - - /** - * 10. - * - Create data key with kmip as provider and master key of { keyId: '1' } - * - Use UUID to encrypt and decrypt to value. - * - Create data key with invalid encrypter and expect failure. - */ - before(async function () { - dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); - encrypted = await clientEncryption.encrypt('test', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: dataKey - }); - decrypted = await clientEncryption.decrypt(encrypted); - }); - - it('must create a data key', function () { - expect(dataKey).to.have.property('sub_type', 4); - }); - - it('properly encrypts and decrypts', function () { - expect(decrypted).to.equal('test'); - }); - - it.only('fails with invalid provider host', async function () { - try { - await clientEncryptionInvalid.createDataKey('kmip', { masterKey }); - } catch (e) { - expect(e.message).to.equal('KMS request failed'); - } - }); - }); - - context('when providing an endpoint in the master key', function () { - context('when the endpoint is valid', function () { - const masterKey = { keyId: '1', endpoint: 'localhost:5698' }; - let dataKey; - let encrypted; - let decrypted; - - /** - * 11. - * - Create data key with kmip as provider and master key of - * { keyId: 1, endpoint: 'localhost:5698 '} - * - Use UUID to encrypt and decrypt to value. - */ - before(async function () { - dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); - encrypted = await clientEncryption.encrypt('test', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: dataKey - }); - decrypted = await clientEncryption.decrypt(encrypted); - }); - - it('must create a data key', function () { - expect(dataKey).to.have.property('sub_type', 4); - }); - - it('properly encrypts and decrypts', function () { - expect(decrypted).to.equal('test'); - }); - }); - - context('when the endpoint is invalid', function () { - const masterKey = { keyId: '1', endpoint: 'doesnotexist.localhost:5698' }; - - /** - * 12. - * - Create data key with kmip as provider and master key of - * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} - * - Expect failure. - */ - it('fails with invalid provider host', async function () { - try { - await clientEncryption.createDataKey('kmip', { masterKey }); - } catch (e) { - expect(e.message).to.equal('KMS request failed'); - } - }); - }); - }); - - }); - }); - - /** - * - Create client encryption no tls - * - Create client encryption with tls - * - Create client encryption expired - * - Create client encryption invalid hostname - */ - context('when passing through tls options', metadata, function () { - const tlsCaOptions = { - aws: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - }, - azure: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - }, - gcp: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - }, - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - } - } - const clientNoTlsOptions = { - kmsProviders: getKmsProviders() - }; - const clientWithTlsOptions = { - kmsProviders: getKmsProviders(), - tlsOptions: { - aws: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - }, - azure: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - }, - gcp: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - }, - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - } - } - }; - const clientWithTlsExpiredOptions = { - kmsProviders: getKmsProviders('127.0.0.1:8000', '127.0.0.1:8000', '127.0.0.1:8000'), - tlsOptions: tlsCaOptions - }; - const clientWithInvalidHostnameOptions = { - kmsProviders: getKmsProviders('127.0.0.1:8001', '127.0.0.1:8001', '127.0.0.1:8001'), - tlsOptions: tlsCaOptions - }; - - let clientNoTls; - let clientWithTls; - let clientWithTlsExpired; - let clientWithInvalidHostname; - - beforeEach(async function () { - clientNoTls = this.configuration.newClient({}, { - autoEncryption: clientNoTlsOptions - }); - clientWithTls = this.configuration.newClient({}, { - autoEncryption: clientWithTlsOptions - }); - clientWithTlsExpired = this.configuration.newClient({}, { - autoEncryption: clientWithTlsExpiredOptions - }); - clientWithInvalidHostname = this.configuration.newClient({}, { - autoEncryption: clientWithInvalidHostnameOptions - }); - }); - - afterEach(async function () { - await clientNoTls.close(true); - await clientWithTls.close(true); - await clientWithTlsExpired.close(true); - await clientWithInvalidHostname.close(true); - }); - - // Case 1. - context('when using aws', function () { - it('must create data keys', function () { - - }); - - it('fails with expired certificates', function () { - - }); - - it('fails with invalid hostnames', function () { - - }); - }); - - // Case 2. - context('when using azure', function () { - it('must create data keys', function () { - - }); - - it('fails with expired certificates', function () { - - }); - - it('fails with invalid hostnames', function () { - - }); - }); - - // Case 3. - context('when using gcp', function () { - it('must create data keys', function () { - - }); - - it('fails with expired certificates', function () { - - }); - - it('fails with invalid hostnames', function () { - - }); - }); - - // Case 4. - context('when using kmip', function () { - it('fails without endpoint', function () { - - }); - - it('must create data keys', function () { - - }); - - it('fails with expired certificates', function () { - - }); - - it('fails with invalid hostnames', function () { - - }); - }); - }); - it('should work for aws KMS provider', metadata, function () { // Then, repeat the above tests with the ``aws`` KMS provider: let awsDatakeyId; From 6205d221ee3d194bec0a8bd9cffef5f0091c8a0e Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 25 Jan 2022 09:54:47 +0100 Subject: [PATCH 23/73] test(NODE-3777): finish csfle prose tests --- .../client_side_encryption.prose.test.js | 259 +++++++++++++++--- 1 file changed, 221 insertions(+), 38 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 599a437fbe1..84700e97709 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -17,7 +17,7 @@ const getKmsProviders = (localKey, kmipEndpoint, azureEndpoint, gcpEndpoint) => }; if (result.azure && azureEndpoint) { - result.azure.endpoint = azureEndpoint; + result.azure.identityPlatformEndpoint = azureEndpoint; } if (result.gcp && gcpEndpoint) { @@ -55,7 +55,7 @@ describe('Client Side Encryption Prose Tests', function () { 'base64' ); - context.only('when kmip is the kms provider', metadata, function () { + context('when kmip is the kms provider', metadata, function () { const autoEncryptionOptions = { keyVaultNamespace, kmsProviders: { @@ -97,7 +97,7 @@ describe('Client Side Encryption Prose Tests', function () { await client.close(true); }); - context.only('when encrypting with kmip', function () { + context('when encrypting with kmip', function () { context('when not providing an endpoint in the master key', function () { const masterKey = { keyId: '1' }; let dataKey; @@ -185,7 +185,6 @@ describe('Client Side Encryption Prose Tests', function () { }); }); }); - }); }); @@ -209,11 +208,13 @@ describe('Client Side Encryption Prose Tests', function () { kmip: { tlsCAFile: process.env.KMIP_TLS_CA_FILE } - } + }; const clientNoTlsOptions = { + keyVaultNamespace, kmsProviders: getKmsProviders() }; const clientWithTlsOptions = { + keyVaultNamespace, kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), tlsOptions: { aws: { @@ -235,10 +236,12 @@ describe('Client Side Encryption Prose Tests', function () { } }; const clientWithTlsExpiredOptions = { + keyVaultNamespace, kmsProviders: getKmsProviders(null, '127.0.0.1:8000', '127.0.0.1:8000', '127.0.0.1:8000'), tlsOptions: tlsCaOptions }; const clientWithInvalidHostnameOptions = { + keyVaultNamespace, kmsProviders: getKmsProviders(null, '127.0.0.1:8001', '127.0.0.1:8001', '127.0.0.1:8001'), tlsOptions: tlsCaOptions }; @@ -248,22 +251,20 @@ describe('Client Side Encryption Prose Tests', function () { let clientWithTlsExpired; let clientWithInvalidHostname; - beforeEach(async function () { - clientNoTls = this.configuration.newClient({}, { - autoEncryption: clientNoTlsOptions - }); - clientWithTls = this.configuration.newClient({}, { - autoEncryption: clientWithTlsOptions - }); - clientWithTlsExpired = this.configuration.newClient({}, { - autoEncryption: clientWithTlsExpiredOptions - }); - clientWithInvalidHostname = this.configuration.newClient({}, { - autoEncryption: clientWithInvalidHostnameOptions - }); + before(async function () { + clientNoTls = this.configuration.newClient({}, { autoEncryption: clientNoTlsOptions }); + clientWithTls = this.configuration.newClient({}, { autoEncryption: clientWithTlsOptions }); + clientWithTlsExpired = this.configuration.newClient( + {}, + { autoEncryption: clientWithTlsExpiredOptions } + ); + clientWithInvalidHostname = this.configuration.newClient( + {}, + { autoEncryption: clientWithInvalidHostnameOptions } + ); }); - afterEach(async function () { + after(async function () { await clientNoTls.close(true); await clientWithTls.close(true); await clientWithTlsExpired.close(true); @@ -272,65 +273,247 @@ describe('Client Side Encryption Prose Tests', function () { // Case 1. context('when using aws', function () { - it('must create data keys', function () { - + const masterKey = { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: '127.0.0.1:8002' + }; + let clientEncryptionNoTls; + let clientEncryptionWithTlsExpired; + let clientEncryptionWithInvalidHostname; + + before(async function () { + await clientNoTls.connect(); + await clientWithTlsExpired.connect(); + await clientWithInvalidHostname.connect(); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { + ...clientNoTlsOptions, + bson: BSON + }); + clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( + clientWithTlsExpired, + { ...clientWithTlsExpiredOptions, bson: BSON } + ); + clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( + clientWithInvalidHostname, + { ...clientWithInvalidHostnameOptions, bson: BSON } + ); }); - it('fails with expired certificates', function () { - + it('fails with no tls', async function () { + try { + await clientEncryptionNoTls.createDataKey('aws', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('self signed certificate'); + } }); - it('fails with invalid hostnames', function () { + it('fails with expired certificates', async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('SSL alert'); + } + }); + it('fails with invalid hostnames', async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('aws', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('SSL alert'); + } }); }); // Case 2. context('when using azure', function () { - it('must create data keys', function () { + const masterKey = { + keyVaultEndpoint: 'doesnotexist.local', + keyName: 'foo' + }; + + let clientEncryptionNoTls; + let clientEncryptionWithTls; + let clientEncryptionWithTlsExpired; + let clientEncryptionWithInvalidHostname; + before(async function () { + await clientNoTls.connect(); + await clientWithTls.connect(); + await clientWithTlsExpired.connect(); + await clientWithInvalidHostname.connect(); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { + ...clientNoTlsOptions, + bson: BSON + }); + clientEncryptionWithTls = new mongodbClientEncryption.ClientEncryption(clientWithTls, { + ...clientWithTlsOptions, + bson: BSON + }); + clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( + clientWithTlsExpired, + { ...clientWithTlsExpiredOptions, bson: BSON } + ); + clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( + clientWithInvalidHostname, + { ...clientWithInvalidHostnameOptions, bson: BSON } + ); }); - it('fails with expired certificates', function () { + it('fails with no tls', async function () { + try { + await clientEncryptionNoTls.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.message).to.include('HTTP status=400'); + } + }); + it('fails with invalid host', async function () { + try { + await clientEncryptionWithTls.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.message).to.include('HTTP status=404'); + } }); - it('fails with invalid hostnames', function () { + it('fails with expired certificates', async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); + it('fails with invalid hostnames', async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } }); }); // Case 3. context('when using gcp', function () { - it('must create data keys', function () { + const masterKey = { + projectId: 'foo', + location: 'bar', + keyRing: 'baz', + keyName: 'foo' + }; + + let clientEncryptionNoTls; + let clientEncryptionWithTls; + let clientEncryptionWithTlsExpired; + let clientEncryptionWithInvalidHostname; + before(async function () { + await clientNoTls.connect(); + await clientWithTlsExpired.connect(); + await clientWithInvalidHostname.connect(); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { + ...clientNoTlsOptions, + bson: BSON + }); + clientEncryptionWithTls = new mongodbClientEncryption.ClientEncryption(clientWithTls, { + ...clientWithTlsOptions, + bson: BSON + }); + clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( + clientWithTlsExpired, + { ...clientWithTlsExpiredOptions, bson: BSON } + ); + clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( + clientWithInvalidHostname, + { ...clientWithInvalidHostnameOptions, bson: BSON } + ); }); - it('fails with expired certificates', function () { + it('fails with no tls', async function () { + try { + await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.message).to.include('HTTP status=403'); + } + }); + it('fails with invalid host', async function () { + try { + await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.message).to.include('HTTP status=404'); + } }); - it('fails with invalid hostnames', function () { + it('fails with expired certificates', async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); + it('fails with invalid hostnames', async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } }); }); // Case 4. context('when using kmip', function () { - it('fails without endpoint', function () { - + const masterKey = {}; + let clientEncryptionNoTls; + let clientEncryptionWithTlsExpired; + let clientEncryptionWithInvalidHostname; + + before(async function () { + await clientNoTls.connect(); + await clientWithTls.connect(); + await clientWithTlsExpired.connect(); + await clientWithInvalidHostname.connect(); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { + ...clientNoTlsOptions, + bson: BSON + }); + clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( + clientWithTlsExpired, + { ...clientWithTlsExpiredOptions, bson: BSON } + ); + clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( + clientWithInvalidHostname, + { ...clientWithInvalidHostnameOptions, bson: BSON } + ); }); - it('must create data keys', function () { - + it('fails with no tls', async function () { + try { + await clientEncryptionNoTls.createDataKey('kmip', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('before secure TLS connection'); + } }); - it('fails with expired certificates', function () { - + it('fails with expired certificates', async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('kmip', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } }); - it('fails with invalid hostnames', function () { - + it('fails with invalid hostnames', async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('kmip', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } }); }); }); From a324bc9e3481c8ec1bec4e716ac4c2430a452458 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 25 Jan 2022 16:54:59 +0100 Subject: [PATCH 24/73] test(NODE-3777): update csfle sha1 --- .evergreen/run-custom-csfle-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/run-custom-csfle-tests.sh b/.evergreen/run-custom-csfle-tests.sh index 0389db4f99d..5d949eeac3f 100644 --- a/.evergreen/run-custom-csfle-tests.sh +++ b/.evergreen/run-custom-csfle-tests.sh @@ -27,7 +27,7 @@ ABS_PATH_TO_PATCH=$(pwd) # CSFLE_GIT_REF - set the git reference to checkout for a custom CSFLE version # CDRIVER_GIT_REF - set the git reference to checkout for a custom CDRIVER version (this is for libbson) -CSFLE_GIT_REF=${CSFLE_GIT_REF:-51fb6d6e4448fba9d6638dc4483062eceb5f1b75} +CSFLE_GIT_REF=${CSFLE_GIT_REF:-4eef9752ed4840ebf89401e5e91ace5e3b0555f1} CDRIVER_GIT_REF=${CDRIVER_GIT_REF:-1.17.6} rm -rf ../csfle-deps-tmp From af92edbc4ab65b85089ad0fa466720935e36c651 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 25 Jan 2022 17:13:58 +0100 Subject: [PATCH 25/73] test(NODE-3777): point to libmongocrypt main branch --- .evergreen/run-custom-csfle-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/run-custom-csfle-tests.sh b/.evergreen/run-custom-csfle-tests.sh index 5d949eeac3f..857c1d3735d 100644 --- a/.evergreen/run-custom-csfle-tests.sh +++ b/.evergreen/run-custom-csfle-tests.sh @@ -27,7 +27,7 @@ ABS_PATH_TO_PATCH=$(pwd) # CSFLE_GIT_REF - set the git reference to checkout for a custom CSFLE version # CDRIVER_GIT_REF - set the git reference to checkout for a custom CDRIVER version (this is for libbson) -CSFLE_GIT_REF=${CSFLE_GIT_REF:-4eef9752ed4840ebf89401e5e91ace5e3b0555f1} +CSFLE_GIT_REF=${CSFLE_GIT_REF:-master} CDRIVER_GIT_REF=${CDRIVER_GIT_REF:-1.17.6} rm -rf ../csfle-deps-tmp From 9c58db6b059329ea01f8cd2ffd1bf118eb96152c Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 26 Jan 2022 03:47:34 +0100 Subject: [PATCH 26/73] test(NODE-3777): adding missing 2 prose tests --- .../client_side_encryption.prose.test.js | 158 ++++++------------ 1 file changed, 50 insertions(+), 108 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 84700e97709..d44c93d49e3 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -250,8 +250,12 @@ describe('Client Side Encryption Prose Tests', function () { let clientWithTls; let clientWithTlsExpired; let clientWithInvalidHostname; + let clientEncryptionNoTls; + let clientEncryptionWithTls; + let clientEncryptionWithTlsExpired; + let clientEncryptionWithInvalidHostname; - before(async function () { + beforeEach(async function () { clientNoTls = this.configuration.newClient({}, { autoEncryption: clientNoTlsOptions }); clientWithTls = this.configuration.newClient({}, { autoEncryption: clientWithTlsOptions }); clientWithTlsExpired = this.configuration.newClient( @@ -262,9 +266,30 @@ describe('Client Side Encryption Prose Tests', function () { {}, { autoEncryption: clientWithInvalidHostnameOptions } ); + await clientNoTls.connect(); + await clientWithTls.connect(); + await clientWithTlsExpired.connect(); + await clientWithInvalidHostname.connect(); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { + ...clientNoTlsOptions, + bson: BSON + }); + clientEncryptionWithTls = new mongodbClientEncryption.ClientEncryption(clientWithTls, { + ...clientWithTlsOptions, + bson: BSON + }); + clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( + clientWithTlsExpired, + { ...clientWithTlsExpiredOptions, bson: BSON } + ); + clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( + clientWithInvalidHostname, + { ...clientWithInvalidHostnameOptions, bson: BSON } + ); }); - after(async function () { + afterEach(async function () { await clientNoTls.close(true); await clientWithTls.close(true); await clientWithTlsExpired.close(true); @@ -278,28 +303,8 @@ describe('Client Side Encryption Prose Tests', function () { key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', endpoint: '127.0.0.1:8002' }; - let clientEncryptionNoTls; - let clientEncryptionWithTlsExpired; - let clientEncryptionWithInvalidHostname; - - before(async function () { - await clientNoTls.connect(); - await clientWithTlsExpired.connect(); - await clientWithInvalidHostname.connect(); - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { - ...clientNoTlsOptions, - bson: BSON - }); - clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( - clientWithTlsExpired, - { ...clientWithTlsExpiredOptions, bson: BSON } - ); - clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( - clientWithInvalidHostname, - { ...clientWithInvalidHostnameOptions, bson: BSON } - ); - }); + const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; + const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; it('fails with no tls', async function () { try { @@ -309,19 +314,27 @@ describe('Client Side Encryption Prose Tests', function () { } }); + it('passes with tls but fails to parse', async function () { + try { + await clientEncryptionWithTls.createDataKey('aws', { masterKey }); + } catch (e) { + expect(e.message).to.include('parse error'); + } + }); + it('fails with expired certificates', async function () { try { - await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKey }); + await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); } catch (e) { - expect(e.originalError.message).to.include('SSL alert'); + expect(e.message).to.include('expected UTF-8 key'); } }); it('fails with invalid hostnames', async function () { try { - await clientEncryptionWithInvalidHostname.createDataKey('aws', { masterKey }); + await clientEncryptionWithInvalidHostname.createDataKey('aws', { masterKeyInvalidHostname }); } catch (e) { - expect(e.originalError.message).to.include('SSL alert'); + expect(e.message).to.include('expected UTF-8 key'); } }); }); @@ -333,35 +346,6 @@ describe('Client Side Encryption Prose Tests', function () { keyName: 'foo' }; - let clientEncryptionNoTls; - let clientEncryptionWithTls; - let clientEncryptionWithTlsExpired; - let clientEncryptionWithInvalidHostname; - - before(async function () { - await clientNoTls.connect(); - await clientWithTls.connect(); - await clientWithTlsExpired.connect(); - await clientWithInvalidHostname.connect(); - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { - ...clientNoTlsOptions, - bson: BSON - }); - clientEncryptionWithTls = new mongodbClientEncryption.ClientEncryption(clientWithTls, { - ...clientWithTlsOptions, - bson: BSON - }); - clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( - clientWithTlsExpired, - { ...clientWithTlsExpiredOptions, bson: BSON } - ); - clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( - clientWithInvalidHostname, - { ...clientWithInvalidHostnameOptions, bson: BSON } - ); - }); - it('fails with no tls', async function () { try { await clientEncryptionNoTls.createDataKey('azure', { masterKey }); @@ -404,34 +388,6 @@ describe('Client Side Encryption Prose Tests', function () { keyName: 'foo' }; - let clientEncryptionNoTls; - let clientEncryptionWithTls; - let clientEncryptionWithTlsExpired; - let clientEncryptionWithInvalidHostname; - - before(async function () { - await clientNoTls.connect(); - await clientWithTlsExpired.connect(); - await clientWithInvalidHostname.connect(); - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { - ...clientNoTlsOptions, - bson: BSON - }); - clientEncryptionWithTls = new mongodbClientEncryption.ClientEncryption(clientWithTls, { - ...clientWithTlsOptions, - bson: BSON - }); - clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( - clientWithTlsExpired, - { ...clientWithTlsExpiredOptions, bson: BSON } - ); - clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( - clientWithInvalidHostname, - { ...clientWithInvalidHostnameOptions, bson: BSON } - ); - }); - it('fails with no tls', async function () { try { await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); @@ -468,29 +424,6 @@ describe('Client Side Encryption Prose Tests', function () { // Case 4. context('when using kmip', function () { const masterKey = {}; - let clientEncryptionNoTls; - let clientEncryptionWithTlsExpired; - let clientEncryptionWithInvalidHostname; - - before(async function () { - await clientNoTls.connect(); - await clientWithTls.connect(); - await clientWithTlsExpired.connect(); - await clientWithInvalidHostname.connect(); - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { - ...clientNoTlsOptions, - bson: BSON - }); - clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( - clientWithTlsExpired, - { ...clientWithTlsExpiredOptions, bson: BSON } - ); - clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( - clientWithInvalidHostname, - { ...clientWithInvalidHostnameOptions, bson: BSON } - ); - }); it('fails with no tls', async function () { try { @@ -500,6 +433,15 @@ describe('Client Side Encryption Prose Tests', function () { } }); + // MongoNotConnectedError: MongoClient must be connected to perform this operation + // Client is being connected in the beforeEach block above, and has no error on + // connect. So why does it say this only in this particular case? We prove this + // works in previous tests for kmip above. + it.skip('passes with tls', async function () { + const dataKey = await clientEncryptionWithTls.createDataKey('kmip', { masterKey }); + expect(dataKey).to.have.property('sub_type', 4); + }); + it('fails with expired certificates', async function () { try { await clientEncryptionWithTlsExpired.createDataKey('kmip', { masterKey }); From 54e1be4ca6c87cc021db73afeaa1803e92133b64 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 26 Jan 2022 07:21:28 +0100 Subject: [PATCH 27/73] test(NODE-3777): fix tls prose setup --- .../client_side_encryption.prose.test.js | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index d44c93d49e3..dd4c7230aa7 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -194,7 +194,7 @@ describe('Client Side Encryption Prose Tests', function () { * - Create client encryption expired * - Create client encryption invalid hostname */ - context('when passing through tls options', metadata, function () { + context.only('when passing through tls options', metadata, function () { const tlsCaOptions = { aws: { tlsCAFile: process.env.KMIP_TLS_CA_FILE @@ -211,7 +211,8 @@ describe('Client Side Encryption Prose Tests', function () { }; const clientNoTlsOptions = { keyVaultNamespace, - kmsProviders: getKmsProviders() + kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), + tlsOptions: tlsCaOptions }; const clientWithTlsOptions = { keyVaultNamespace, @@ -255,6 +256,13 @@ describe('Client Side Encryption Prose Tests', function () { let clientEncryptionWithTlsExpired; let clientEncryptionWithInvalidHostname; + before(function () { + console.log('clientNoTlsOptions', clientNoTlsOptions); + console.log('clientWithTlsOptions', clientWithTlsOptions); + console.log('clientWithTlsExpiredOptions', clientWithTlsExpiredOptions); + console.log('clientWithInvalidHostnameOptions', clientWithInvalidHostnameOptions); + }); + beforeEach(async function () { clientNoTls = this.configuration.newClient({}, { autoEncryption: clientNoTlsOptions }); clientWithTls = this.configuration.newClient({}, { autoEncryption: clientWithTlsOptions }); @@ -310,7 +318,7 @@ describe('Client Side Encryption Prose Tests', function () { try { await clientEncryptionNoTls.createDataKey('aws', { masterKey }); } catch (e) { - expect(e.originalError.message).to.include('self signed certificate'); + expect(e.originalError.message).to.include('certificate required'); } }); @@ -326,7 +334,7 @@ describe('Client Side Encryption Prose Tests', function () { try { await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); } catch (e) { - expect(e.message).to.include('expected UTF-8 key'); + expect(e.originalError.message).to.include('expected UTF-8 key'); } }); @@ -334,7 +342,7 @@ describe('Client Side Encryption Prose Tests', function () { try { await clientEncryptionWithInvalidHostname.createDataKey('aws', { masterKeyInvalidHostname }); } catch (e) { - expect(e.message).to.include('expected UTF-8 key'); + expect(e.originalError.message).to.include('expected UTF-8 key'); } }); }); @@ -350,7 +358,7 @@ describe('Client Side Encryption Prose Tests', function () { try { await clientEncryptionNoTls.createDataKey('azure', { masterKey }); } catch (e) { - expect(e.message).to.include('HTTP status=400'); + expect(e.originalError.message).to.include('certificate required'); } }); @@ -392,7 +400,7 @@ describe('Client Side Encryption Prose Tests', function () { try { await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); } catch (e) { - expect(e.message).to.include('HTTP status=403'); + expect(e.originalError.message).to.include('certificate required'); } }); @@ -437,7 +445,7 @@ describe('Client Side Encryption Prose Tests', function () { // Client is being connected in the beforeEach block above, and has no error on // connect. So why does it say this only in this particular case? We prove this // works in previous tests for kmip above. - it.skip('passes with tls', async function () { + it('passes with tls', async function () { const dataKey = await clientEncryptionWithTls.createDataKey('kmip', { masterKey }); expect(dataKey).to.have.property('sub_type', 4); }); From bd71820bba3d9ef5795a9a1348f20b0113c247f0 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 26 Jan 2022 07:37:49 +0100 Subject: [PATCH 28/73] test(NODE-3777): fix tls prose setup for aws --- .../client_side_encryption.prose.test.js | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index dd4c7230aa7..a44bd4155ee 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -274,10 +274,6 @@ describe('Client Side Encryption Prose Tests', function () { {}, { autoEncryption: clientWithInvalidHostnameOptions } ); - await clientNoTls.connect(); - await clientWithTls.connect(); - await clientWithTlsExpired.connect(); - await clientWithInvalidHostname.connect(); const mongodbClientEncryption = this.configuration.mongodbClientEncryption; clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { ...clientNoTlsOptions, @@ -295,6 +291,10 @@ describe('Client Side Encryption Prose Tests', function () { clientWithInvalidHostname, { ...clientWithInvalidHostnameOptions, bson: BSON } ); + await clientNoTls.connect(); + await clientWithTls.connect(); + await clientWithTlsExpired.connect(); + await clientWithInvalidHostname.connect(); }); afterEach(async function () { @@ -334,7 +334,7 @@ describe('Client Side Encryption Prose Tests', function () { try { await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); } catch (e) { - expect(e.originalError.message).to.include('expected UTF-8 key'); + expect(e.message).to.include('expected UTF-8 key'); } }); @@ -342,7 +342,7 @@ describe('Client Side Encryption Prose Tests', function () { try { await clientEncryptionWithInvalidHostname.createDataKey('aws', { masterKeyInvalidHostname }); } catch (e) { - expect(e.originalError.message).to.include('expected UTF-8 key'); + expect(e.message).to.include('expected UTF-8 key'); } }); }); @@ -431,11 +431,9 @@ describe('Client Side Encryption Prose Tests', function () { // Case 4. context('when using kmip', function () { - const masterKey = {}; - it('fails with no tls', async function () { try { - await clientEncryptionNoTls.createDataKey('kmip', { masterKey }); + await clientEncryptionNoTls.createDataKey('kmip'); } catch (e) { expect(e.originalError.message).to.include('before secure TLS connection'); } @@ -446,13 +444,13 @@ describe('Client Side Encryption Prose Tests', function () { // connect. So why does it say this only in this particular case? We prove this // works in previous tests for kmip above. it('passes with tls', async function () { - const dataKey = await clientEncryptionWithTls.createDataKey('kmip', { masterKey }); + const dataKey = await clientEncryptionWithTls.createDataKey('kmip'); expect(dataKey).to.have.property('sub_type', 4); }); it('fails with expired certificates', async function () { try { - await clientEncryptionWithTlsExpired.createDataKey('kmip', { masterKey }); + await clientEncryptionWithTlsExpired.createDataKey('kmip'); } catch (e) { expect(e.originalError.message).to.include('certificate has expired'); } @@ -460,7 +458,7 @@ describe('Client Side Encryption Prose Tests', function () { it('fails with invalid hostnames', async function () { try { - await clientEncryptionWithInvalidHostname.createDataKey('kmip', { masterKey }); + await clientEncryptionWithInvalidHostname.createDataKey('kmip'); } catch (e) { expect(e.originalError.message).to.include('does not match certificate'); } From d55cac6c8717658d8da98b9f77ae6aab114910a8 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 26 Jan 2022 08:27:42 +0100 Subject: [PATCH 29/73] test(NODE-3777): reorder connect/close --- .../client_side_encryption.prose.test.js | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index a44bd4155ee..36802043caf 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -91,10 +91,12 @@ describe('Client Side Encryption Prose Tests', function () { } } }); + await dropCollection(client.db(keyVaultDbName), keyVaultCollName); + await dropCollection(client.db(keyVaultDbName), keyVaultCollName); }); after(async function () { - await client.close(true); + await client.close(); }); context('when encrypting with kmip', function () { @@ -194,7 +196,7 @@ describe('Client Side Encryption Prose Tests', function () { * - Create client encryption expired * - Create client encryption invalid hostname */ - context.only('when passing through tls options', metadata, function () { + context('when passing through tls options', metadata, function () { const tlsCaOptions = { aws: { tlsCAFile: process.env.KMIP_TLS_CA_FILE @@ -256,13 +258,6 @@ describe('Client Side Encryption Prose Tests', function () { let clientEncryptionWithTlsExpired; let clientEncryptionWithInvalidHostname; - before(function () { - console.log('clientNoTlsOptions', clientNoTlsOptions); - console.log('clientWithTlsOptions', clientWithTlsOptions); - console.log('clientWithTlsExpiredOptions', clientWithTlsExpiredOptions); - console.log('clientWithInvalidHostnameOptions', clientWithInvalidHostnameOptions); - }); - beforeEach(async function () { clientNoTls = this.configuration.newClient({}, { autoEncryption: clientNoTlsOptions }); clientWithTls = this.configuration.newClient({}, { autoEncryption: clientWithTlsOptions }); @@ -295,13 +290,15 @@ describe('Client Side Encryption Prose Tests', function () { await clientWithTls.connect(); await clientWithTlsExpired.connect(); await clientWithInvalidHostname.connect(); + await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); + await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); }); afterEach(async function () { - await clientNoTls.close(true); - await clientWithTls.close(true); - await clientWithTlsExpired.close(true); - await clientWithInvalidHostname.close(true); + await clientNoTls.close(); + await clientWithTls.close(); + await clientWithTlsExpired.close(); + await clientWithInvalidHostname.close(); }); // Case 1. From fb4f81e98cdc0f9a0f4d29fcb4b98ac900f804e0 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 31 Jan 2022 15:31:01 +0100 Subject: [PATCH 30/73] test(NODE-3777): explicitly close client --- .../client_side_encryption.prose.test.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 36802043caf..35cfec1cae4 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -258,7 +258,7 @@ describe('Client Side Encryption Prose Tests', function () { let clientEncryptionWithTlsExpired; let clientEncryptionWithInvalidHostname; - beforeEach(async function () { + before(async function () { clientNoTls = this.configuration.newClient({}, { autoEncryption: clientNoTlsOptions }); clientWithTls = this.configuration.newClient({}, { autoEncryption: clientWithTlsOptions }); clientWithTlsExpired = this.configuration.newClient( @@ -294,7 +294,7 @@ describe('Client Side Encryption Prose Tests', function () { await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); }); - afterEach(async function () { + after(async function () { await clientNoTls.close(); await clientWithTls.close(); await clientWithTlsExpired.close(); @@ -428,6 +428,13 @@ describe('Client Side Encryption Prose Tests', function () { // Case 4. context('when using kmip', function () { + it('passes with tls', async function () { + const dataKey = await clientEncryptionWithTls.createDataKey('kmip'); + // TODO: NODE-3927 + await clientWithTls.close(); + expect(dataKey).to.have.property('sub_type', 4); + }); + it('fails with no tls', async function () { try { await clientEncryptionNoTls.createDataKey('kmip'); @@ -436,15 +443,6 @@ describe('Client Side Encryption Prose Tests', function () { } }); - // MongoNotConnectedError: MongoClient must be connected to perform this operation - // Client is being connected in the beforeEach block above, and has no error on - // connect. So why does it say this only in this particular case? We prove this - // works in previous tests for kmip above. - it('passes with tls', async function () { - const dataKey = await clientEncryptionWithTls.createDataKey('kmip'); - expect(dataKey).to.have.property('sub_type', 4); - }); - it('fails with expired certificates', async function () { try { await clientEncryptionWithTlsExpired.createDataKey('kmip'); From 4a7235374ff49aba686566f91ae5065abd3fa57d Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 31 Jan 2022 17:18:43 +0100 Subject: [PATCH 31/73] fix(NODE-3777): lint errors and use beta 3 --- .evergreen/run-custom-csfle-tests.sh | 6 ------ .evergreen/run-tests.sh | 2 +- .../client_side_encryption.prose.test.js | 4 +++- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.evergreen/run-custom-csfle-tests.sh b/.evergreen/run-custom-csfle-tests.sh index 857c1d3735d..f15c1b2f94d 100644 --- a/.evergreen/run-custom-csfle-tests.sh +++ b/.evergreen/run-custom-csfle-tests.sh @@ -105,9 +105,3 @@ if [ $DRIVER_CSFLE_TEST_RESULT -ne 0 ]; then echo "Driver tests failed, look above for results" exit 1 fi - -# These will now obviously fail as KMIP doesn't exist in the old bindings. -# echo "Test legacy version of FLE bindings" -# rm -rf node_modules/mongodb-client-encryption -# npm install mongodb-client-encryption@"^1.2.7" -# npm run check:csfle diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index c7d3667416e..abc801a4c97 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -41,7 +41,7 @@ if [[ -z "${CLIENT_ENCRYPTION}" ]]; then unset AWS_ACCESS_KEY_ID; unset AWS_SECRET_ACCESS_KEY; else - npm install mongodb-client-encryption@">=2.0.0-beta.2" + npm install mongodb-client-encryption@">=2.0.0-beta.3" pip install --upgrade boto3 # Get access to the AWS temporary credentials: diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 35cfec1cae4..d749e75fafb 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -337,7 +337,9 @@ describe('Client Side Encryption Prose Tests', function () { it('fails with invalid hostnames', async function () { try { - await clientEncryptionWithInvalidHostname.createDataKey('aws', { masterKeyInvalidHostname }); + await clientEncryptionWithInvalidHostname.createDataKey('aws', { + masterKeyInvalidHostname + }); } catch (e) { expect(e.message).to.include('expected UTF-8 key'); } From 00bb60301bc1209c2dd3360bcf508bee27ad03a3 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 31 Jan 2022 18:32:30 +0100 Subject: [PATCH 32/73] fix(NODE-3777): run kms servers on regular tests --- .evergreen/config.yml | 16 ++++++++++++++++ .evergreen/config.yml.in | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index fa675834113..6f2608df672 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -100,6 +100,22 @@ functions: ${PREPARE_SHELL} DRIVERS_TOOLS="${DRIVERS_TOOLS}" bash ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/run-mongohouse-local.sh run tests: + - command: shell.exec + params: + background: true + script: > + cd ${DRIVERS_TOOLS}/.evergreen/csfle + + ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & + + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem + --port 8000 & + + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file + ../x509gen/wrong-host.pem --port 8001 & + + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem + --port 8002 --require_client_cert & - command: shell.exec type: test params: diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index 99d8ffe5dcb..dd3678d07f3 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -120,6 +120,15 @@ functions: DRIVERS_TOOLS="${DRIVERS_TOOLS}" bash ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/run-mongohouse-local.sh "run tests": + - command: shell.exec + params: + background: true + script: | + cd ${DRIVERS_TOOLS}/.evergreen/csfle + ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & - command: shell.exec type: test params: From 321a3305df089cdac8ba581765883545c463d334 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 31 Jan 2022 18:33:36 +0100 Subject: [PATCH 33/73] fix(NODE-3777): run kms servers on regular tests --- .evergreen/config.yml | 22 +++++++++------------- .evergreen/config.yml.in | 13 ++++++++----- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 6f2608df672..08f1f986e0a 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -103,19 +103,15 @@ functions: - command: shell.exec params: background: true - script: > - cd ${DRIVERS_TOOLS}/.evergreen/csfle - - ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & - - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem - --port 8000 & - - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file - ../x509gen/wrong-host.pem --port 8001 & - - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem - --port 8002 --require_client_cert & + script: | + if [ -n "${CLIENT_ENCRYPTION}" ]; then + cd ${DRIVERS_TOOLS}/.evergreen/csfle + ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & + EOT + fi - command: shell.exec type: test params: diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index dd3678d07f3..a58469406bb 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -124,11 +124,14 @@ functions: params: background: true script: | - cd ${DRIVERS_TOOLS}/.evergreen/csfle - ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & + if [ -n "${CLIENT_ENCRYPTION}" ]; then + cd ${DRIVERS_TOOLS}/.evergreen/csfle + ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & + EOT + fi - command: shell.exec type: test params: From 3d98db9db4060418226976c97ed154f4cd6b9820 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 1 Feb 2022 09:52:23 +0100 Subject: [PATCH 34/73] fix(NODE-3777): active venx --- .evergreen/config.yml | 9 ++++++++- .evergreen/config.yml.in | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 08f1f986e0a..601b3a8b358 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -100,6 +100,14 @@ functions: ${PREPARE_SHELL} DRIVERS_TOOLS="${DRIVERS_TOOLS}" bash ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/run-mongohouse-local.sh run tests: + - command: shell.exec + params: + script: | + ${PREPARE_SHELL} + if [ -n "${CLIENT_ENCRYPTION}" ]; then + cd ${DRIVERS_TOOLS}/.evergreen/csfle + . ./activate_venv.sh + fi - command: shell.exec params: background: true @@ -110,7 +118,6 @@ functions: ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & - EOT fi - command: shell.exec type: test diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index a58469406bb..7e6fa912448 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -120,6 +120,14 @@ functions: DRIVERS_TOOLS="${DRIVERS_TOOLS}" bash ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/run-mongohouse-local.sh "run tests": + - command: shell.exec + params: + script: | + ${PREPARE_SHELL} + if [ -n "${CLIENT_ENCRYPTION}" ]; then + cd ${DRIVERS_TOOLS}/.evergreen/csfle + . ./activate_venv.sh + fi - command: shell.exec params: background: true @@ -130,7 +138,6 @@ functions: ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & - EOT fi - command: shell.exec type: test From 7b31407c4fece236e7077c57c13fa599735804e3 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 1 Feb 2022 10:41:16 +0100 Subject: [PATCH 35/73] test(NODE-3777): more missing vars in evg --- .evergreen/config.yml | 2 ++ .evergreen/config.yml.in | 2 ++ test/manual/kerberos.test.js | 1 - 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 601b3a8b358..9d9b0edf5f1 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -132,6 +132,8 @@ functions: export AWS_ACCESS_KEY_ID='${AWS_ACCESS_KEY_ID}' export AWS_SECRET_ACCESS_KEY='${AWS_SECRET_ACCESS_KEY}' export AWS_DEFAULT_REGION='us-east-1' + export KMIP_TLS_CA_FILE="${DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem" + export KMIP_TLS_CERT_FILE="${DRIVERS_TOOLS}/.evergreen/x509gen/client.pem" EOT fi - command: shell.exec diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index 7e6fa912448..22c24932110 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -152,6 +152,8 @@ functions: export AWS_ACCESS_KEY_ID='${AWS_ACCESS_KEY_ID}' export AWS_SECRET_ACCESS_KEY='${AWS_SECRET_ACCESS_KEY}' export AWS_DEFAULT_REGION='us-east-1' + export KMIP_TLS_CA_FILE="${DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem" + export KMIP_TLS_CERT_FILE="${DRIVERS_TOOLS}/.evergreen/x509gen/client.pem" EOT fi - command: shell.exec diff --git a/test/manual/kerberos.test.js b/test/manual/kerberos.test.js index 32764d19f07..bfc3294a2fc 100644 --- a/test/manual/kerberos.test.js +++ b/test/manual/kerberos.test.js @@ -51,7 +51,6 @@ describe('Kerberos', function () { }); }); - // Unskip this test when a proper setup is available - see NODE-3060 it.skip('validate that SERVICE_REALM and CANONICALIZE_HOST_NAME can be passed in', function (done) { const client = new MongoClient( `${krb5Uri}&authMechanismProperties=SERVICE_NAME:mongodb,CANONICALIZE_HOST_NAME:false,SERVICE_REALM:windows&maxPoolSize=1` From 009900a62e871b510b9bf5142f3da740cc1afd15 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 1 Feb 2022 12:05:23 +0100 Subject: [PATCH 36/73] fix(NODE-3777): update metadata in prose test --- .../client_side_encryption.prose.test.js | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index d749e75fafb..a98495a399a 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -28,6 +28,7 @@ const getKmsProviders = (localKey, kmipEndpoint, azureEndpoint, gcpEndpoint) => }; const noop = () => {}; +const metadata = { requires: { clientSideEncryption: true, mongodb: '>=4.2.0' } }; // Tests for the ClientEncryption type are not included as part of the YAML tests. @@ -37,8 +38,7 @@ const noop = () => {}; // Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk -describe('Client Side Encryption Prose Tests', function () { - const metadata = { requires: { clientSideEncryption: true, mongodb: '>=4.2.0' } }; +describe('Client Side Encryption Prose Tests', metadata, function () { const dataDbName = 'db'; const dataCollName = 'coll'; const dataNamespace = `${dataDbName}.${dataCollName}`; @@ -99,8 +99,8 @@ describe('Client Side Encryption Prose Tests', function () { await client.close(); }); - context('when encrypting with kmip', function () { - context('when not providing an endpoint in the master key', function () { + context('when encrypting with kmip', metadata, function () { + context('when not providing an endpoint in the master key', metadata, function () { const masterKey = { keyId: '1' }; let dataKey; let encrypted; @@ -121,15 +121,15 @@ describe('Client Side Encryption Prose Tests', function () { decrypted = await clientEncryption.decrypt(encrypted); }); - it('must create a data key', function () { + it('must create a data key', metadata, function () { expect(dataKey).to.have.property('sub_type', 4); }); - it('properly encrypts and decrypts', function () { + it('properly encrypts and decrypts', metadata, function () { expect(decrypted).to.equal('test'); }); - it('fails with invalid provider host', async function () { + it('fails with invalid provider host', metadata, async function () { try { await clientEncryptionInvalid.createDataKey('kmip', { masterKey }); } catch (e) { @@ -138,8 +138,8 @@ describe('Client Side Encryption Prose Tests', function () { }); }); - context('when providing an endpoint in the master key', function () { - context('when the endpoint is valid', function () { + context('when providing an endpoint in the master key', metadata, function () { + context('when the endpoint is valid', metadata, function () { const masterKey = { keyId: '1', endpoint: 'localhost:5698' }; let dataKey; let encrypted; @@ -160,16 +160,16 @@ describe('Client Side Encryption Prose Tests', function () { decrypted = await clientEncryption.decrypt(encrypted); }); - it('must create a data key', function () { + it('must create a data key', metadata, function () { expect(dataKey).to.have.property('sub_type', 4); }); - it('properly encrypts and decrypts', function () { + it('properly encrypts and decrypts', metadata, function () { expect(decrypted).to.equal('test'); }); }); - context('when the endpoint is invalid', function () { + context('when the endpoint is invalid', metadata, function () { const masterKey = { keyId: '1', endpoint: 'doesnotexist.localhost:5698' }; /** @@ -178,7 +178,7 @@ describe('Client Side Encryption Prose Tests', function () { * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} * - Expect failure. */ - it('fails with invalid provider host', async function () { + it('fails with invalid provider host', metadata, async function () { try { await clientEncryption.createDataKey('kmip', { masterKey }); } catch (e) { @@ -302,7 +302,7 @@ describe('Client Side Encryption Prose Tests', function () { }); // Case 1. - context('when using aws', function () { + context('when using aws', metadata, function () { const masterKey = { region: 'us-east-1', key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', @@ -311,7 +311,7 @@ describe('Client Side Encryption Prose Tests', function () { const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; - it('fails with no tls', async function () { + it('fails with no tls', metadata, async function () { try { await clientEncryptionNoTls.createDataKey('aws', { masterKey }); } catch (e) { @@ -319,7 +319,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('passes with tls but fails to parse', async function () { + it('passes with tls but fails to parse', metadata, async function () { try { await clientEncryptionWithTls.createDataKey('aws', { masterKey }); } catch (e) { @@ -327,7 +327,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('fails with expired certificates', async function () { + it('fails with expired certificates', metadata, async function () { try { await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); } catch (e) { @@ -335,7 +335,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('fails with invalid hostnames', async function () { + it('fails with invalid hostnames', metadata, async function () { try { await clientEncryptionWithInvalidHostname.createDataKey('aws', { masterKeyInvalidHostname @@ -347,13 +347,13 @@ describe('Client Side Encryption Prose Tests', function () { }); // Case 2. - context('when using azure', function () { + context('when using azure', metadata, function () { const masterKey = { keyVaultEndpoint: 'doesnotexist.local', keyName: 'foo' }; - it('fails with no tls', async function () { + it('fails with no tls', metadata, async function () { try { await clientEncryptionNoTls.createDataKey('azure', { masterKey }); } catch (e) { @@ -361,7 +361,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('fails with invalid host', async function () { + it('fails with invalid host', metadata, async function () { try { await clientEncryptionWithTls.createDataKey('azure', { masterKey }); } catch (e) { @@ -369,7 +369,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('fails with expired certificates', async function () { + it('fails with expired certificates', metadata, async function () { try { await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); } catch (e) { @@ -377,7 +377,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('fails with invalid hostnames', async function () { + it('fails with invalid hostnames', metadata, async function () { try { await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); } catch (e) { @@ -387,7 +387,7 @@ describe('Client Side Encryption Prose Tests', function () { }); // Case 3. - context('when using gcp', function () { + context('when using gcp', metadata, function () { const masterKey = { projectId: 'foo', location: 'bar', @@ -395,7 +395,7 @@ describe('Client Side Encryption Prose Tests', function () { keyName: 'foo' }; - it('fails with no tls', async function () { + it('fails with no tls', metadata, async function () { try { await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); } catch (e) { @@ -403,7 +403,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('fails with invalid host', async function () { + it('fails with invalid host', metadata, async function () { try { await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); } catch (e) { @@ -411,7 +411,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('fails with expired certificates', async function () { + it('fails with expired certificates', metadata, async function () { try { await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); } catch (e) { @@ -419,7 +419,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('fails with invalid hostnames', async function () { + it('fails with invalid hostnames', metadata, async function () { try { await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); } catch (e) { @@ -429,7 +429,7 @@ describe('Client Side Encryption Prose Tests', function () { }); // Case 4. - context('when using kmip', function () { + context('when using kmip', metadata, function () { it('passes with tls', async function () { const dataKey = await clientEncryptionWithTls.createDataKey('kmip'); // TODO: NODE-3927 @@ -437,7 +437,7 @@ describe('Client Side Encryption Prose Tests', function () { expect(dataKey).to.have.property('sub_type', 4); }); - it('fails with no tls', async function () { + it('fails with no tls', metadata, async function () { try { await clientEncryptionNoTls.createDataKey('kmip'); } catch (e) { @@ -445,7 +445,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('fails with expired certificates', async function () { + it('fails with expired certificates', metadata, async function () { try { await clientEncryptionWithTlsExpired.createDataKey('kmip'); } catch (e) { @@ -453,7 +453,7 @@ describe('Client Side Encryption Prose Tests', function () { } }); - it('fails with invalid hostnames', async function () { + it('fails with invalid hostnames', metadata, async function () { try { await clientEncryptionWithInvalidHostname.createDataKey('kmip'); } catch (e) { From a54b2d9bf5547d0f25ddebd82afac9faa823ecb2 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 1 Feb 2022 16:46:07 +0100 Subject: [PATCH 37/73] fix(NODE-3777): remove bad test --- .../client_side_encryption.prose.test.js | 296 +++++++++--------- 1 file changed, 147 insertions(+), 149 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index a98495a399a..169f6097e42 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -286,179 +286,177 @@ describe('Client Side Encryption Prose Tests', metadata, function () { clientWithInvalidHostname, { ...clientWithInvalidHostnameOptions, bson: BSON } ); - await clientNoTls.connect(); - await clientWithTls.connect(); - await clientWithTlsExpired.connect(); - await clientWithInvalidHostname.connect(); - await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); - await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); }); - after(async function () { - await clientNoTls.close(); - await clientWithTls.close(); - await clientWithTlsExpired.close(); - await clientWithInvalidHostname.close(); - }); - - // Case 1. - context('when using aws', metadata, function () { - const masterKey = { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: '127.0.0.1:8002' - }; - const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; - const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; - - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('aws', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } + context('when using tls clients', metadata, function () { + beforeEach('connecting tls clients', async function () { + await clientNoTls.connect(); + await clientWithTls.connect(); + await clientWithTlsExpired.connect(); + await clientWithInvalidHostname.connect(); + await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); + await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); }); - it('passes with tls but fails to parse', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('aws', { masterKey }); - } catch (e) { - expect(e.message).to.include('parse error'); - } + afterEach(async function () { + await clientNoTls.close(); + await clientWithTls.close(); + await clientWithTlsExpired.close(); + await clientWithInvalidHostname.close(); }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); - } catch (e) { - expect(e.message).to.include('expected UTF-8 key'); - } - }); + // Case 1. + context('when using aws', metadata, function () { + const masterKey = { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: '127.0.0.1:8002' + }; + const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; + const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('aws', { - masterKeyInvalidHostname - }); - } catch (e) { - expect(e.message).to.include('expected UTF-8 key'); - } - }); - }); + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('aws', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } + }); - // Case 2. - context('when using azure', metadata, function () { - const masterKey = { - keyVaultEndpoint: 'doesnotexist.local', - keyName: 'foo' - }; + it('passes with tls but fails to parse', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('aws', { masterKey }); + } catch (e) { + expect(e.message).to.include('parse error'); + } + }); - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); + } catch (e) { + expect(e.message).to.include('expected UTF-8 key'); + } + }); - it('fails with invalid host', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.message).to.include('HTTP status=404'); - } + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('aws', { + masterKeyInvalidHostname + }); + } catch (e) { + expect(e.message).to.include('expected UTF-8 key'); + } + }); }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } - }); + // Case 2. + context('when using azure', metadata, function () { + const masterKey = { + keyVaultEndpoint: 'doesnotexist.local', + keyName: 'foo' + }; - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } - }); - }); + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } + }); - // Case 3. - context('when using gcp', metadata, function () { - const masterKey = { - projectId: 'foo', - location: 'bar', - keyRing: 'baz', - keyName: 'foo' - }; + it('fails with invalid host', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.message).to.include('HTTP status=404'); + } + }); - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); - it('fails with invalid host', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.message).to.include('HTTP status=404'); - } + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } + }); }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } - }); + // Case 3. + context('when using gcp', metadata, function () { + const masterKey = { + projectId: 'foo', + location: 'bar', + keyRing: 'baz', + keyName: 'foo' + }; - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } - }); - }); + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } + }); - // Case 4. - context('when using kmip', metadata, function () { - it('passes with tls', async function () { - const dataKey = await clientEncryptionWithTls.createDataKey('kmip'); - // TODO: NODE-3927 - await clientWithTls.close(); - expect(dataKey).to.have.property('sub_type', 4); - }); + it('fails with invalid host', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.message).to.include('HTTP status=404'); + } + }); - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('kmip'); - } catch (e) { - expect(e.originalError.message).to.include('before secure TLS connection'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('kmip'); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } + }); }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('kmip'); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } + // Case 4. + context('when using kmip', metadata, function () { + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('kmip'); + } catch (e) { + expect(e.originalError.message).to.include('before secure TLS connection'); + } + }); + + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('kmip'); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); + + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('kmip'); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } + }); }); }); }); From e253a9f211157745ee99225bfd68b5b60614f02a Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 3 Feb 2022 13:52:22 +0100 Subject: [PATCH 38/73] test(NODE-3777): bootstrap kms servers --- .evergreen/config.yml | 63 ++++++++++++++++---------- .evergreen/config.yml.in | 18 +------- .evergreen/generate_evergreen_tasks.js | 3 ++ 3 files changed, 45 insertions(+), 39 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 9d9b0edf5f1..47a7770d26d 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -99,7 +99,7 @@ functions: script: | ${PREPARE_SHELL} DRIVERS_TOOLS="${DRIVERS_TOOLS}" bash ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/run-mongohouse-local.sh - run tests: + bootstrap kms servers: - command: shell.exec params: script: | @@ -119,6 +119,7 @@ functions: ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & fi + run tests: - command: shell.exec type: test params: @@ -679,28 +680,6 @@ functions: export CSFLE_GIT_REF="${CSFLE_GIT_REF}" export CDRIVER_GIT_REF="${CDRIVER_GIT_REF}" EOT - - command: shell.exec - params: - script: | - ${PREPARE_SHELL} - cd ${DRIVERS_TOOLS}/.evergreen/csfle - . ./activate_venv.sh - - command: shell.exec - params: - background: true - script: > - cd ${DRIVERS_TOOLS}/.evergreen/csfle - - ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & - - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem - --port 8000 & - - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file - ../x509gen/wrong-host.pem --port 8001 & - - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem - --port 8002 --require_client_cert & - command: shell.exec type: test params: @@ -793,6 +772,7 @@ tasks: VERSION: latest TOPOLOGY: server AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-latest-replica_set tags: @@ -805,6 +785,7 @@ tasks: VERSION: latest TOPOLOGY: replica_set AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-latest-sharded_cluster tags: @@ -817,6 +798,7 @@ tasks: VERSION: latest TOPOLOGY: sharded_cluster AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-5.0-server tags: @@ -829,6 +811,7 @@ tasks: VERSION: '5.0' TOPOLOGY: server AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-5.0-replica_set tags: @@ -841,6 +824,7 @@ tasks: VERSION: '5.0' TOPOLOGY: replica_set AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-5.0-sharded_cluster tags: @@ -853,6 +837,7 @@ tasks: VERSION: '5.0' TOPOLOGY: sharded_cluster AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-4.4-server tags: @@ -865,6 +850,7 @@ tasks: VERSION: '4.4' TOPOLOGY: server AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-4.4-replica_set tags: @@ -877,6 +863,7 @@ tasks: VERSION: '4.4' TOPOLOGY: replica_set AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-4.4-sharded_cluster tags: @@ -889,6 +876,7 @@ tasks: VERSION: '4.4' TOPOLOGY: sharded_cluster AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-4.2-server tags: @@ -901,6 +889,7 @@ tasks: VERSION: '4.2' TOPOLOGY: server AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-4.2-replica_set tags: @@ -913,6 +902,7 @@ tasks: VERSION: '4.2' TOPOLOGY: replica_set AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-4.2-sharded_cluster tags: @@ -925,6 +915,7 @@ tasks: VERSION: '4.2' TOPOLOGY: sharded_cluster AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-4.0-server tags: @@ -937,6 +928,7 @@ tasks: VERSION: '4.0' TOPOLOGY: server AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-4.0-replica_set tags: @@ -949,6 +941,7 @@ tasks: VERSION: '4.0' TOPOLOGY: replica_set AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-4.0-sharded_cluster tags: @@ -961,6 +954,7 @@ tasks: VERSION: '4.0' TOPOLOGY: sharded_cluster AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-3.6-server tags: @@ -973,6 +967,7 @@ tasks: VERSION: '3.6' TOPOLOGY: server AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-3.6-replica_set tags: @@ -985,6 +980,7 @@ tasks: VERSION: '3.6' TOPOLOGY: replica_set AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-3.6-sharded_cluster tags: @@ -997,6 +993,7 @@ tasks: VERSION: '3.6' TOPOLOGY: sharded_cluster AUTH: auth + - func: bootstrap kms servers - func: run tests - name: test-latest-server-v1-api tags: @@ -1040,6 +1037,7 @@ tasks: AUTH: auth LOAD_BALANCER: 'true' - func: start-load-balancer + - func: bootstrap kms servers - func: run-lb-tests - func: stop-load-balancer - name: test-auth-kerberos @@ -1064,6 +1062,7 @@ tasks: vars: VERSION: latest TOPOLOGY: replica_set + - func: bootstrap kms servers - func: run socks5 tests - name: test-socks5-tls tags: [] @@ -1819,6 +1818,7 @@ tasks: VERSION: latest TOPOLOGY: server AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-latest-replica_set-noauth tags: @@ -1832,6 +1832,7 @@ tasks: VERSION: latest TOPOLOGY: replica_set AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-latest-sharded_cluster-noauth tags: @@ -1845,6 +1846,7 @@ tasks: VERSION: latest TOPOLOGY: sharded_cluster AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-5.0-server-noauth tags: @@ -1858,6 +1860,7 @@ tasks: VERSION: '5.0' TOPOLOGY: server AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-5.0-replica_set-noauth tags: @@ -1871,6 +1874,7 @@ tasks: VERSION: '5.0' TOPOLOGY: replica_set AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-5.0-sharded_cluster-noauth tags: @@ -1884,6 +1888,7 @@ tasks: VERSION: '5.0' TOPOLOGY: sharded_cluster AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-4.4-server-noauth tags: @@ -1897,6 +1902,7 @@ tasks: VERSION: '4.4' TOPOLOGY: server AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-4.4-replica_set-noauth tags: @@ -1910,6 +1916,7 @@ tasks: VERSION: '4.4' TOPOLOGY: replica_set AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-4.4-sharded_cluster-noauth tags: @@ -1923,6 +1930,7 @@ tasks: VERSION: '4.4' TOPOLOGY: sharded_cluster AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-4.2-server-noauth tags: @@ -1936,6 +1944,7 @@ tasks: VERSION: '4.2' TOPOLOGY: server AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-4.2-replica_set-noauth tags: @@ -1949,6 +1958,7 @@ tasks: VERSION: '4.2' TOPOLOGY: replica_set AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-4.2-sharded_cluster-noauth tags: @@ -1962,6 +1972,7 @@ tasks: VERSION: '4.2' TOPOLOGY: sharded_cluster AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-4.0-server-noauth tags: @@ -1975,6 +1986,7 @@ tasks: VERSION: '4.0' TOPOLOGY: server AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-4.0-replica_set-noauth tags: @@ -1988,6 +2000,7 @@ tasks: VERSION: '4.0' TOPOLOGY: replica_set AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-4.0-sharded_cluster-noauth tags: @@ -2001,6 +2014,7 @@ tasks: VERSION: '4.0' TOPOLOGY: sharded_cluster AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-3.6-server-noauth tags: @@ -2014,6 +2028,7 @@ tasks: VERSION: '3.6' TOPOLOGY: server AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-3.6-replica_set-noauth tags: @@ -2027,6 +2042,7 @@ tasks: VERSION: '3.6' TOPOLOGY: replica_set AUTH: noauth + - func: bootstrap kms servers - func: run tests - name: test-3.6-sharded_cluster-noauth tags: @@ -2040,6 +2056,7 @@ tasks: VERSION: '3.6' TOPOLOGY: sharded_cluster AUTH: noauth + - func: bootstrap kms servers - func: run tests task_groups: - name: serverless_task_group diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index 22c24932110..cf3bab336fd 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -119,7 +119,7 @@ functions: ${PREPARE_SHELL} DRIVERS_TOOLS="${DRIVERS_TOOLS}" bash ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/run-mongohouse-local.sh - "run tests": + "bootstrap kms servers": - command: shell.exec params: script: | @@ -139,6 +139,7 @@ functions: ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & fi + "run tests": - command: shell.exec type: test params: @@ -708,21 +709,6 @@ functions: export CSFLE_GIT_REF="${CSFLE_GIT_REF}" export CDRIVER_GIT_REF="${CDRIVER_GIT_REF}" EOT - - command: shell.exec - params: - script: | - ${PREPARE_SHELL} - cd ${DRIVERS_TOOLS}/.evergreen/csfle - . ./activate_venv.sh - - command: shell.exec - params: - background: true - script: | - cd ${DRIVERS_TOOLS}/.evergreen/csfle - ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & - command: shell.exec type: test params: diff --git a/.evergreen/generate_evergreen_tasks.js b/.evergreen/generate_evergreen_tasks.js index bb2e154ea2a..dd92de7137b 100644 --- a/.evergreen/generate_evergreen_tasks.js +++ b/.evergreen/generate_evergreen_tasks.js @@ -62,6 +62,7 @@ function makeTask({ mongoVersion, topology, tags = [], auth = 'auth' }) { AUTH: auth } }, + { func: 'bootstrap kms servers' }, { func: 'run tests' } ] }; @@ -137,6 +138,7 @@ TASKS.push( } }, { func: 'start-load-balancer' }, + { func: 'bootstrap kms servers' }, { func: 'run-lb-tests' }, { func: 'stop-load-balancer' } ] @@ -163,6 +165,7 @@ TASKS.push( TOPOLOGY: 'replica_set' } }, + { func: 'bootstrap kms servers' }, { func: 'run socks5 tests' } ] }, From 12b5654f320fa1892046afc48573aa015292409f Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 3 Feb 2022 14:41:23 +0100 Subject: [PATCH 39/73] test(NODE-3777): add csfle to lb tests --- .evergreen/config.yml | 15 +++++++++++++++ .evergreen/config.yml.in | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 47a7770d26d..ee10182c7b6 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -205,6 +205,21 @@ functions: DRIVERS_TOOLS=${DRIVERS_TOOLS} MONGODB_URI=${MONGODB_URI} \ bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh stop run-lb-tests: + - command: shell.exec + type: test + params: + silent: true + working_dir: src + script: | + ${PREPARE_SHELL} + cat < prepare_client_encryption.sh + export CLIENT_ENCRYPTION=${CLIENT_ENCRYPTION} + export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}' + export AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID}" + export AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY}" + export CSFLE_GIT_REF="${CSFLE_GIT_REF}" + export CDRIVER_GIT_REF="${CDRIVER_GIT_REF}" + EOT - command: shell.exec type: test params: diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index cf3bab336fd..69c77cef5e4 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -229,6 +229,21 @@ functions: bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh stop "run-lb-tests": + - command: shell.exec + type: test + params: + silent: true + working_dir: "src" + script: | + ${PREPARE_SHELL} + cat < prepare_client_encryption.sh + export CLIENT_ENCRYPTION=${CLIENT_ENCRYPTION} + export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}' + export AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID}" + export AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY}" + export CSFLE_GIT_REF="${CSFLE_GIT_REF}" + export CDRIVER_GIT_REF="${CDRIVER_GIT_REF}" + EOT - command: shell.exec type: test params: From 22d60e0564438729d1afbdf035c47149f6ebce4a Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 3 Feb 2022 14:58:16 +0100 Subject: [PATCH 40/73] test(NODE-3777): update lb env --- .evergreen/config.yml | 5 +++++ .evergreen/config.yml.in | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index ee10182c7b6..9373fa3de3d 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -228,6 +228,11 @@ functions: script: | ${PREPARE_SHELL} + # Disable xtrace (just in case it was accidentally set). + set +x + . ./prepare_client_encryption.sh + rm -f ./prepare_client_encryption.sh + MONGODB_URI="${MONGODB_URI}" \ AUTH=${AUTH} \ SSL=${SSL} \ diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index 69c77cef5e4..df5bd124378 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -252,6 +252,11 @@ functions: script: | ${PREPARE_SHELL} + # Disable xtrace (just in case it was accidentally set). + set +x + . ./prepare_client_encryption.sh + rm -f ./prepare_client_encryption.sh + MONGODB_URI="${MONGODB_URI}" \ AUTH=${AUTH} \ SSL=${SSL} \ From 2e084149c58ecde7aedb25ee5309bf8092d0475d Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 3 Feb 2022 15:20:33 +0100 Subject: [PATCH 41/73] test(NODE-3777): run kms server with v1 api tests --- .evergreen/config.yml | 1 + .evergreen/generate_evergreen_tasks.js | 1 + 2 files changed, 2 insertions(+) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 9373fa3de3d..3cb5df94a42 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -1028,6 +1028,7 @@ tasks: TOPOLOGY: server REQUIRE_API_VERSION: '1' AUTH: auth + - func: bootstrap kms servers - func: run tests vars: MONGODB_API_VERSION: '1' diff --git a/.evergreen/generate_evergreen_tasks.js b/.evergreen/generate_evergreen_tasks.js index dd92de7137b..3835fc30144 100644 --- a/.evergreen/generate_evergreen_tasks.js +++ b/.evergreen/generate_evergreen_tasks.js @@ -97,6 +97,7 @@ BASE_TASKS.push({ AUTH: 'auth' } }, + { func: 'bootstrap kms servers' }, { func: 'run tests', vars: { From af1658bf6d13d78e18b9c99582aa530d2726f75d Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 3 Feb 2022 15:56:05 +0100 Subject: [PATCH 42/73] test(NODE-3777): no csfle on lb tests --- .evergreen/config.yml | 21 ------------------- .evergreen/config.yml.in | 20 ------------------ .evergreen/generate_evergreen_tasks.js | 1 - .../client_side_encryption.prose.test.js | 8 ++++++- 4 files changed, 7 insertions(+), 43 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 3cb5df94a42..19b217679e6 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -205,21 +205,6 @@ functions: DRIVERS_TOOLS=${DRIVERS_TOOLS} MONGODB_URI=${MONGODB_URI} \ bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh stop run-lb-tests: - - command: shell.exec - type: test - params: - silent: true - working_dir: src - script: | - ${PREPARE_SHELL} - cat < prepare_client_encryption.sh - export CLIENT_ENCRYPTION=${CLIENT_ENCRYPTION} - export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}' - export AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID}" - export AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY}" - export CSFLE_GIT_REF="${CSFLE_GIT_REF}" - export CDRIVER_GIT_REF="${CDRIVER_GIT_REF}" - EOT - command: shell.exec type: test params: @@ -228,11 +213,6 @@ functions: script: | ${PREPARE_SHELL} - # Disable xtrace (just in case it was accidentally set). - set +x - . ./prepare_client_encryption.sh - rm -f ./prepare_client_encryption.sh - MONGODB_URI="${MONGODB_URI}" \ AUTH=${AUTH} \ SSL=${SSL} \ @@ -1058,7 +1038,6 @@ tasks: AUTH: auth LOAD_BALANCER: 'true' - func: start-load-balancer - - func: bootstrap kms servers - func: run-lb-tests - func: stop-load-balancer - name: test-auth-kerberos diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index df5bd124378..cf3bab336fd 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -229,21 +229,6 @@ functions: bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh stop "run-lb-tests": - - command: shell.exec - type: test - params: - silent: true - working_dir: "src" - script: | - ${PREPARE_SHELL} - cat < prepare_client_encryption.sh - export CLIENT_ENCRYPTION=${CLIENT_ENCRYPTION} - export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}' - export AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID}" - export AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY}" - export CSFLE_GIT_REF="${CSFLE_GIT_REF}" - export CDRIVER_GIT_REF="${CDRIVER_GIT_REF}" - EOT - command: shell.exec type: test params: @@ -252,11 +237,6 @@ functions: script: | ${PREPARE_SHELL} - # Disable xtrace (just in case it was accidentally set). - set +x - . ./prepare_client_encryption.sh - rm -f ./prepare_client_encryption.sh - MONGODB_URI="${MONGODB_URI}" \ AUTH=${AUTH} \ SSL=${SSL} \ diff --git a/.evergreen/generate_evergreen_tasks.js b/.evergreen/generate_evergreen_tasks.js index 3835fc30144..d3ac4132c0d 100644 --- a/.evergreen/generate_evergreen_tasks.js +++ b/.evergreen/generate_evergreen_tasks.js @@ -139,7 +139,6 @@ TASKS.push( } }, { func: 'start-load-balancer' }, - { func: 'bootstrap kms servers' }, { func: 'run-lb-tests' }, { func: 'stop-load-balancer' } ] diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 169f6097e42..559c3ac650e 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -28,7 +28,13 @@ const getKmsProviders = (localKey, kmipEndpoint, azureEndpoint, gcpEndpoint) => }; const noop = () => {}; -const metadata = { requires: { clientSideEncryption: true, mongodb: '>=4.2.0' } }; +const metadata = { + requires: { + clientSideEncryption: true, + mongodb: '>=4.2.0', + topology: '!load-balanced' + } +}; // Tests for the ClientEncryption type are not included as part of the YAML tests. From 3659ad62a55033ef25696c9a3a4f36ca52e87417 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 3 Feb 2022 16:26:46 +0100 Subject: [PATCH 43/73] test(NODE-3777): move options setting --- .../client_side_encryption.prose.test.js | 108 +++++++++--------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 559c3ac650e..9fed95c636c 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -203,58 +203,11 @@ describe('Client Side Encryption Prose Tests', metadata, function () { * - Create client encryption invalid hostname */ context('when passing through tls options', metadata, function () { - const tlsCaOptions = { - aws: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - }, - azure: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - }, - gcp: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - }, - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - } - }; - const clientNoTlsOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), - tlsOptions: tlsCaOptions - }; - const clientWithTlsOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), - tlsOptions: { - aws: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - }, - azure: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - }, - gcp: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - }, - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - } - } - }; - const clientWithTlsExpiredOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, '127.0.0.1:8000', '127.0.0.1:8000', '127.0.0.1:8000'), - tlsOptions: tlsCaOptions - }; - const clientWithInvalidHostnameOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, '127.0.0.1:8001', '127.0.0.1:8001', '127.0.0.1:8001'), - tlsOptions: tlsCaOptions - }; - + let tlsCaOptions; + let clientNoTlsOptions; + let clientWithTlsOptions; + let clientWithTlsExpiredOptions; + let clientWithInvalidHostnameOptions; let clientNoTls; let clientWithTls; let clientWithTlsExpired; @@ -265,6 +218,57 @@ describe('Client Side Encryption Prose Tests', metadata, function () { let clientEncryptionWithInvalidHostname; before(async function () { + tlsCaOptions = { + aws: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + azure: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + gcp: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + } + }; + clientNoTlsOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), + tlsOptions: tlsCaOptions + }; + clientWithTlsOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), + tlsOptions: { + aws: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + azure: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + gcp: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } + }; + clientWithTlsExpiredOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, '127.0.0.1:8000', '127.0.0.1:8000', '127.0.0.1:8000'), + tlsOptions: tlsCaOptions + }; + clientWithInvalidHostnameOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, '127.0.0.1:8001', '127.0.0.1:8001', '127.0.0.1:8001'), + tlsOptions: tlsCaOptions + }; clientNoTls = this.configuration.newClient({}, { autoEncryption: clientNoTlsOptions }); clientWithTls = this.configuration.newClient({}, { autoEncryption: clientWithTlsOptions }); clientWithTlsExpired = this.configuration.newClient( From cf1650309c3cbe85b192340db144a1209461aed1 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 3 Feb 2022 16:48:59 +0100 Subject: [PATCH 44/73] test(NODE-3777): check topology filter on evg --- .../client_side_encryption.prose.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 9fed95c636c..819f123d1f1 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -61,7 +61,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { 'base64' ); - context('when kmip is the kms provider', metadata, function () { + context('when kmip is the kms provider', metadata, async function () { const autoEncryptionOptions = { keyVaultNamespace, kmsProviders: { @@ -105,8 +105,8 @@ describe('Client Side Encryption Prose Tests', metadata, function () { await client.close(); }); - context('when encrypting with kmip', metadata, function () { - context('when not providing an endpoint in the master key', metadata, function () { + context('when encrypting with kmip', metadata, async function () { + context('when not providing an endpoint in the master key', metadata, async function () { const masterKey = { keyId: '1' }; let dataKey; let encrypted; @@ -202,7 +202,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { * - Create client encryption expired * - Create client encryption invalid hostname */ - context('when passing through tls options', metadata, function () { + context('when passing through tls options', metadata, async function () { let tlsCaOptions; let clientNoTlsOptions; let clientWithTlsOptions; From d69646ee1be73337f57fd4fab00e73186184e311 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 3 Feb 2022 20:56:58 +0100 Subject: [PATCH 45/73] test(NODE-3777): dont default to invalid json --- .../client-side-encryption/client_side_encryption.prose.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 819f123d1f1..593d8a8f1ab 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -8,7 +8,7 @@ chai.use(require('chai-subset')); const { LEGACY_HELLO_COMMAND } = require('../../../src/constants'); const getKmsProviders = (localKey, kmipEndpoint, azureEndpoint, gcpEndpoint) => { - const result = BSON.EJSON.parse(process.env.CSFLE_KMS_PROVIDERS || 'NOT_PROVIDED'); + const result = BSON.EJSON.parse(process.env.CSFLE_KMS_PROVIDERS || '{}'); if (localKey) { result.local = { key: localKey }; } From c68c9e0c0899061cbe53ceccc31e577b264abd02 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Fri, 4 Feb 2022 10:50:25 +0100 Subject: [PATCH 46/73] test(NODE-3777): force skip in lb mode --- .../client_side_encryption.prose.test.js | 2486 +++++++++-------- 1 file changed, 1244 insertions(+), 1242 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 593d8a8f1ab..99a40a11320 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -43,119 +43,81 @@ const metadata = { // .. code:: javascript // Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk - -describe('Client Side Encryption Prose Tests', metadata, function () { - const dataDbName = 'db'; - const dataCollName = 'coll'; - const dataNamespace = `${dataDbName}.${dataCollName}`; - const keyVaultDbName = 'keyvault'; - const keyVaultCollName = 'datakeys'; - const keyVaultNamespace = `${keyVaultDbName}.${keyVaultCollName}`; - - const shared = require('../shared'); - const dropCollection = shared.dropCollection; - const APMEventCollector = shared.APMEventCollector; - - const LOCAL_KEY = Buffer.from( - 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk', - 'base64' - ); - - context('when kmip is the kms provider', metadata, async function () { - const autoEncryptionOptions = { - keyVaultNamespace, - kmsProviders: { - kmip: { - endpoint: 'localhost:5698' - } - }, - tlsOptions: { - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - } - } - }; - let client; - let clientEncryption; - let clientEncryptionInvalid; - - before(async function () { - client = this.configuration.newClient(); - await client.connect(); - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - clientEncryption = new mongodbClientEncryption.ClientEncryption(client, { - ...autoEncryptionOptions, - bson: BSON - }); - clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(client, { - ...autoEncryptionOptions, - bson: BSON, +// TODO: NODE-3927 - these cannot run in lb mode but are not skipping based on metadata. +if (!process.env.LOAD_BALANCER) { + describe('Client Side Encryption Prose Tests', metadata, function () { + const dataDbName = 'db'; + const dataCollName = 'coll'; + const dataNamespace = `${dataDbName}.${dataCollName}`; + const keyVaultDbName = 'keyvault'; + const keyVaultCollName = 'datakeys'; + const keyVaultNamespace = `${keyVaultDbName}.${keyVaultCollName}`; + + const shared = require('../shared'); + const dropCollection = shared.dropCollection; + const APMEventCollector = shared.APMEventCollector; + + const LOCAL_KEY = Buffer.from( + 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk', + 'base64' + ); + + context('when kmip is the kms provider', metadata, async function () { + const autoEncryptionOptions = { + keyVaultNamespace, kmsProviders: { kmip: { - endpoint: 'invalid.localhost:5698' + endpoint: 'localhost:5698' + } + }, + tlsOptions: { + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE } } - }); - await dropCollection(client.db(keyVaultDbName), keyVaultCollName); - await dropCollection(client.db(keyVaultDbName), keyVaultCollName); - }); - - after(async function () { - await client.close(); - }); - - context('when encrypting with kmip', metadata, async function () { - context('when not providing an endpoint in the master key', metadata, async function () { - const masterKey = { keyId: '1' }; - let dataKey; - let encrypted; - let decrypted; - - /** - * 10. - * - Create data key with kmip as provider and master key of { keyId: '1' } - * - Use UUID to encrypt and decrypt to value. - * - Create data key with invalid encrypter and expect failure. - */ - before(async function () { - dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); - encrypted = await clientEncryption.encrypt('test', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: dataKey - }); - decrypted = await clientEncryption.decrypt(encrypted); - }); - - it('must create a data key', metadata, function () { - expect(dataKey).to.have.property('sub_type', 4); - }); + }; + let client; + let clientEncryption; + let clientEncryptionInvalid; - it('properly encrypts and decrypts', metadata, function () { - expect(decrypted).to.equal('test'); + before(async function () { + client = this.configuration.newClient(); + await client.connect(); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + clientEncryption = new mongodbClientEncryption.ClientEncryption(client, { + ...autoEncryptionOptions, + bson: BSON }); - - it('fails with invalid provider host', metadata, async function () { - try { - await clientEncryptionInvalid.createDataKey('kmip', { masterKey }); - } catch (e) { - expect(e.message).to.equal('KMS request failed'); + clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(client, { + ...autoEncryptionOptions, + bson: BSON, + kmsProviders: { + kmip: { + endpoint: 'invalid.localhost:5698' + } } }); + await dropCollection(client.db(keyVaultDbName), keyVaultCollName); + await dropCollection(client.db(keyVaultDbName), keyVaultCollName); + }); + + after(async function () { + await client.close(); }); - context('when providing an endpoint in the master key', metadata, function () { - context('when the endpoint is valid', metadata, function () { - const masterKey = { keyId: '1', endpoint: 'localhost:5698' }; + context('when encrypting with kmip', metadata, async function () { + context('when not providing an endpoint in the master key', metadata, async function () { + const masterKey = { keyId: '1' }; let dataKey; let encrypted; let decrypted; /** - * 11. - * - Create data key with kmip as provider and master key of - * { keyId: 1, endpoint: 'localhost:5698 '} + * 10. + * - Create data key with kmip as provider and master key of { keyId: '1' } * - Use UUID to encrypt and decrypt to value. + * - Create data key with invalid encrypter and expect failure. */ before(async function () { dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); @@ -173,1273 +135,1313 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('properly encrypts and decrypts', metadata, function () { expect(decrypted).to.equal('test'); }); - }); - - context('when the endpoint is invalid', metadata, function () { - const masterKey = { keyId: '1', endpoint: 'doesnotexist.localhost:5698' }; - /** - * 12. - * - Create data key with kmip as provider and master key of - * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} - * - Expect failure. - */ it('fails with invalid provider host', metadata, async function () { try { - await clientEncryption.createDataKey('kmip', { masterKey }); + await clientEncryptionInvalid.createDataKey('kmip', { masterKey }); } catch (e) { expect(e.message).to.equal('KMS request failed'); } }); }); + + context('when providing an endpoint in the master key', metadata, function () { + context('when the endpoint is valid', metadata, function () { + const masterKey = { keyId: '1', endpoint: 'localhost:5698' }; + let dataKey; + let encrypted; + let decrypted; + + /** + * 11. + * - Create data key with kmip as provider and master key of + * { keyId: 1, endpoint: 'localhost:5698 '} + * - Use UUID to encrypt and decrypt to value. + */ + before(async function () { + dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); + encrypted = await clientEncryption.encrypt('test', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: dataKey + }); + decrypted = await clientEncryption.decrypt(encrypted); + }); + + it('must create a data key', metadata, function () { + expect(dataKey).to.have.property('sub_type', 4); + }); + + it('properly encrypts and decrypts', metadata, function () { + expect(decrypted).to.equal('test'); + }); + }); + + context('when the endpoint is invalid', metadata, function () { + const masterKey = { keyId: '1', endpoint: 'doesnotexist.localhost:5698' }; + + /** + * 12. + * - Create data key with kmip as provider and master key of + * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} + * - Expect failure. + */ + it('fails with invalid provider host', metadata, async function () { + try { + await clientEncryption.createDataKey('kmip', { masterKey }); + } catch (e) { + expect(e.message).to.equal('KMS request failed'); + } + }); + }); + }); }); }); - }); - /** - * - Create client encryption no tls - * - Create client encryption with tls - * - Create client encryption expired - * - Create client encryption invalid hostname - */ - context('when passing through tls options', metadata, async function () { - let tlsCaOptions; - let clientNoTlsOptions; - let clientWithTlsOptions; - let clientWithTlsExpiredOptions; - let clientWithInvalidHostnameOptions; - let clientNoTls; - let clientWithTls; - let clientWithTlsExpired; - let clientWithInvalidHostname; - let clientEncryptionNoTls; - let clientEncryptionWithTls; - let clientEncryptionWithTlsExpired; - let clientEncryptionWithInvalidHostname; - - before(async function () { - tlsCaOptions = { - aws: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - }, - azure: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - }, - gcp: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - }, - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE - } - }; - clientNoTlsOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), - tlsOptions: tlsCaOptions - }; - clientWithTlsOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), - tlsOptions: { + /** + * - Create client encryption no tls + * - Create client encryption with tls + * - Create client encryption expired + * - Create client encryption invalid hostname + */ + context('when passing through tls options', metadata, async function () { + let tlsCaOptions; + let clientNoTlsOptions; + let clientWithTlsOptions; + let clientWithTlsExpiredOptions; + let clientWithInvalidHostnameOptions; + let clientNoTls; + let clientWithTls; + let clientWithTlsExpired; + let clientWithInvalidHostname; + let clientEncryptionNoTls; + let clientEncryptionWithTls; + let clientEncryptionWithTlsExpired; + let clientEncryptionWithInvalidHostname; + + before(async function () { + tlsCaOptions = { aws: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + tlsCAFile: process.env.KMIP_TLS_CA_FILE }, azure: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + tlsCAFile: process.env.KMIP_TLS_CA_FILE }, gcp: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + tlsCAFile: process.env.KMIP_TLS_CA_FILE }, kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + tlsCAFile: process.env.KMIP_TLS_CA_FILE } - } - }; - clientWithTlsExpiredOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, '127.0.0.1:8000', '127.0.0.1:8000', '127.0.0.1:8000'), - tlsOptions: tlsCaOptions - }; - clientWithInvalidHostnameOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, '127.0.0.1:8001', '127.0.0.1:8001', '127.0.0.1:8001'), - tlsOptions: tlsCaOptions - }; - clientNoTls = this.configuration.newClient({}, { autoEncryption: clientNoTlsOptions }); - clientWithTls = this.configuration.newClient({}, { autoEncryption: clientWithTlsOptions }); - clientWithTlsExpired = this.configuration.newClient( - {}, - { autoEncryption: clientWithTlsExpiredOptions } - ); - clientWithInvalidHostname = this.configuration.newClient( - {}, - { autoEncryption: clientWithInvalidHostnameOptions } - ); - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { - ...clientNoTlsOptions, - bson: BSON - }); - clientEncryptionWithTls = new mongodbClientEncryption.ClientEncryption(clientWithTls, { - ...clientWithTlsOptions, - bson: BSON - }); - clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( - clientWithTlsExpired, - { ...clientWithTlsExpiredOptions, bson: BSON } - ); - clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( - clientWithInvalidHostname, - { ...clientWithInvalidHostnameOptions, bson: BSON } - ); - }); - - context('when using tls clients', metadata, function () { - beforeEach('connecting tls clients', async function () { - await clientNoTls.connect(); - await clientWithTls.connect(); - await clientWithTlsExpired.connect(); - await clientWithInvalidHostname.connect(); - await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); - await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); - }); - - afterEach(async function () { - await clientNoTls.close(); - await clientWithTls.close(); - await clientWithTlsExpired.close(); - await clientWithInvalidHostname.close(); - }); - - // Case 1. - context('when using aws', metadata, function () { - const masterKey = { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: '127.0.0.1:8002' }; - const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; - const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; - - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('aws', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); + clientNoTlsOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), + tlsOptions: tlsCaOptions + }; + clientWithTlsOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), + tlsOptions: { + aws: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + azure: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + gcp: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + }, + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } } + }; + clientWithTlsExpiredOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, '127.0.0.1:8000', '127.0.0.1:8000', '127.0.0.1:8000'), + tlsOptions: tlsCaOptions + }; + clientWithInvalidHostnameOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, '127.0.0.1:8001', '127.0.0.1:8001', '127.0.0.1:8001'), + tlsOptions: tlsCaOptions + }; + clientNoTls = this.configuration.newClient({}, { autoEncryption: clientNoTlsOptions }); + clientWithTls = this.configuration.newClient({}, { autoEncryption: clientWithTlsOptions }); + clientWithTlsExpired = this.configuration.newClient( + {}, + { autoEncryption: clientWithTlsExpiredOptions } + ); + clientWithInvalidHostname = this.configuration.newClient( + {}, + { autoEncryption: clientWithInvalidHostnameOptions } + ); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { + ...clientNoTlsOptions, + bson: BSON }); - - it('passes with tls but fails to parse', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('aws', { masterKey }); - } catch (e) { - expect(e.message).to.include('parse error'); - } + clientEncryptionWithTls = new mongodbClientEncryption.ClientEncryption(clientWithTls, { + ...clientWithTlsOptions, + bson: BSON }); + clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( + clientWithTlsExpired, + { ...clientWithTlsExpiredOptions, bson: BSON } + ); + clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( + clientWithInvalidHostname, + { ...clientWithInvalidHostnameOptions, bson: BSON } + ); + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); - } catch (e) { - expect(e.message).to.include('expected UTF-8 key'); - } + context('when using tls clients', metadata, function () { + beforeEach('connecting tls clients', async function () { + await clientNoTls.connect(); + await clientWithTls.connect(); + await clientWithTlsExpired.connect(); + await clientWithInvalidHostname.connect(); + await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); + await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('aws', { - masterKeyInvalidHostname - }); - } catch (e) { - expect(e.message).to.include('expected UTF-8 key'); - } + afterEach(async function () { + await clientNoTls.close(); + await clientWithTls.close(); + await clientWithTlsExpired.close(); + await clientWithInvalidHostname.close(); }); - }); - // Case 2. - context('when using azure', metadata, function () { - const masterKey = { - keyVaultEndpoint: 'doesnotexist.local', - keyName: 'foo' - }; + // Case 1. + context('when using aws', metadata, function () { + const masterKey = { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: '127.0.0.1:8002' + }; + const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; + const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } - }); + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('aws', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } + }); - it('fails with invalid host', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.message).to.include('HTTP status=404'); - } - }); + it('passes with tls but fails to parse', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('aws', { masterKey }); + } catch (e) { + expect(e.message).to.include('parse error'); + } + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); + } catch (e) { + expect(e.message).to.include('expected UTF-8 key'); + } + }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('aws', { + masterKeyInvalidHostname + }); + } catch (e) { + expect(e.message).to.include('expected UTF-8 key'); + } + }); }); - }); - // Case 3. - context('when using gcp', metadata, function () { - const masterKey = { - projectId: 'foo', - location: 'bar', - keyRing: 'baz', - keyName: 'foo' - }; + // Case 2. + context('when using azure', metadata, function () { + const masterKey = { + keyVaultEndpoint: 'doesnotexist.local', + keyName: 'foo' + }; - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } - }); + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } + }); - it('fails with invalid host', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.message).to.include('HTTP status=404'); - } - }); + it('fails with invalid host', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.message).to.include('HTTP status=404'); + } + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } + }); }); - }); - // Case 4. - context('when using kmip', metadata, function () { - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('kmip'); - } catch (e) { - expect(e.originalError.message).to.include('before secure TLS connection'); - } - }); + // Case 3. + context('when using gcp', metadata, function () { + const masterKey = { + projectId: 'foo', + location: 'bar', + keyRing: 'baz', + keyName: 'foo' + }; - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('kmip'); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } + }); + + it('fails with invalid host', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.message).to.include('HTTP status=404'); + } + }); + + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); + + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } + }); }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('kmip'); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } + // Case 4. + context('when using kmip', metadata, function () { + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('kmip'); + } catch (e) { + expect(e.originalError.message).to.include('before secure TLS connection'); + } + }); + + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('kmip'); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); + + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('kmip'); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } + }); }); }); }); - }); - describe('Data key and double encryption', function () { - // Data key and double encryption - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // First, perform the setup. - beforeEach(function () { - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + describe('Data key and double encryption', function () { + // Data key and double encryption + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // First, perform the setup. + beforeEach(function () { + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - // #. Create a MongoClient without encryption enabled (referred to as ``client``). Enable command monitoring to listen for command_started events. - this.client = this.configuration.newClient({}, { monitorCommands: true }); + // #. Create a MongoClient without encryption enabled (referred to as ``client``). Enable command monitoring to listen for command_started events. + this.client = this.configuration.newClient({}, { monitorCommands: true }); - this.commandStartedEvents = new APMEventCollector(this.client, 'commandStarted', { - exclude: [LEGACY_HELLO_COMMAND] - }); + this.commandStartedEvents = new APMEventCollector(this.client, 'commandStarted', { + exclude: [LEGACY_HELLO_COMMAND] + }); - const schemaMap = { - [dataNamespace]: { - bsonType: 'object', - properties: { - encrypted_placeholder: { - encrypt: { - keyId: '/placeholder', - bsonType: 'string', - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Random' + const schemaMap = { + [dataNamespace]: { + bsonType: 'object', + properties: { + encrypted_placeholder: { + encrypt: { + keyId: '/placeholder', + bsonType: 'string', + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Random' + } } } } + }; + + return ( + Promise.resolve() + .then(() => this.client.connect()) + // #. Using ``client``, drop the collections ``keyvault.datakeys`` and ``db.coll``. + .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) + .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) + // #. Create the following: + // - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) + // - A ``ClientEncryption`` object (referred to as ``client_encryption``) + // Configure both objects with ``aws`` and the ``local`` KMS providers as follows: + // .. code:: javascript + // { + // "aws": { }, + // "local": { "key": } + // } + // Configure both objects with ``keyVaultNamespace`` set to ``keyvault.datakeys``. + // Configure the ``MongoClient`` with the following ``schema_map``: + // .. code:: javascript + // { + // "db.coll": { + // "bsonType": "object", + // "properties": { + // "encrypted_placeholder": { + // "encrypt": { + // "keyId": "/placeholder", + // "bsonType": "string", + // "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + // } + // } + // } + // } + // } + // Configure ``client_encryption`` with the ``keyVaultClient`` of the previously created ``client``. + .then(() => { + this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { + kmsProviders: getKmsProviders(), + keyVaultNamespace + }); + }) + .then(() => { + this.clientEncrypted = this.configuration.newClient( + {}, + { + autoEncryption: { + keyVaultNamespace, + kmsProviders: getKmsProviders(), + schemaMap + } + } + ); + return this.clientEncrypted.connect(); + }) + ); + }); + + afterEach(function () { + if (this.commandStartedEvents) { + this.commandStartedEvents.teardown(); + this.commandStartedEvents = undefined; } - }; + return Promise.resolve() + .then(() => this.clientEncrypted && this.clientEncrypted.close()) + .then(() => this.client && this.client.close()); + }); - return ( - Promise.resolve() - .then(() => this.client.connect()) - // #. Using ``client``, drop the collections ``keyvault.datakeys`` and ``db.coll``. - .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) - .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) - // #. Create the following: - // - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) - // - A ``ClientEncryption`` object (referred to as ``client_encryption``) - // Configure both objects with ``aws`` and the ``local`` KMS providers as follows: - // .. code:: javascript - // { - // "aws": { }, - // "local": { "key": } - // } - // Configure both objects with ``keyVaultNamespace`` set to ``keyvault.datakeys``. - // Configure the ``MongoClient`` with the following ``schema_map``: - // .. code:: javascript - // { - // "db.coll": { - // "bsonType": "object", - // "properties": { - // "encrypted_placeholder": { - // "encrypt": { - // "keyId": "/placeholder", - // "bsonType": "string", - // "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" - // } - // } - // } - // } - // } - // Configure ``client_encryption`` with the ``keyVaultClient`` of the previously created ``client``. + it('should work for local KMS provider', metadata, function () { + let localDatakeyId; + let localEncrypted; + return Promise.resolve() .then(() => { - this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { - kmsProviders: getKmsProviders(), - keyVaultNamespace - }); + // #. Call ``client_encryption.createDataKey()`` with the ``local`` KMS provider and keyAltNames set to ``["local_altname"]``. + // - Expect a BSON binary with subtype 4 to be returned, referred to as ``local_datakey_id``. + // - Use ``client`` to run a ``find`` on ``keyvault.datakeys`` by querying with the ``_id`` set to the ``local_datakey_id``. + // - Expect that exactly one document is returned with the "masterKey.provider" equal to "local". + // - Check that ``client`` captured a command_started event for the ``insert`` command containing a majority writeConcern. + this.commandStartedEvents.clear(); + return this.clientEncryption + .createDataKey('local', { keyAltNames: ['local_altname'] }) + .then(result => { + localDatakeyId = result; + expect(localDatakeyId).to.have.property('sub_type', 4); + }) + .then(() => { + return this.client + .db(keyVaultDbName) + .collection(keyVaultCollName) + .find({ _id: localDatakeyId }) + .toArray(); + }) + .then(results => { + expect(results) + .to.have.a.lengthOf(1) + .and.to.have.nested.property('0.masterKey.provider', 'local'); + expect(this.commandStartedEvents.events).to.containSubset([ + { commandName: 'insert', command: { writeConcern: { w: 'majority' } } } + ]); + }); }) .then(() => { - this.clientEncrypted = this.configuration.newClient( - {}, - { - autoEncryption: { - keyVaultNamespace, - kmsProviders: getKmsProviders(), - schemaMap - } - } - ); - return this.clientEncrypted.connect(); + // #. Call ``client_encryption.encrypt()`` with the value "hello local", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_id`` of ``local_datakey_id``. + // - Expect the return value to be a BSON binary subtype 6, referred to as ``local_encrypted``. + // - Use ``client_encrypted`` to insert ``{ _id: "local", "value": }`` into ``db.coll``. + // - Use ``client_encrypted`` to run a find querying with ``_id`` of "local" and expect ``value`` to be "hello local". + const coll = this.clientEncrypted.db(dataDbName).collection(dataCollName); + return this.clientEncryption + .encrypt('hello local', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: localDatakeyId + }) + .then(value => { + localEncrypted = value; + expect(localEncrypted).to.have.property('sub_type', 6); + }) + .then(() => coll.insertOne({ _id: 'local', value: localEncrypted })) + .then(() => coll.findOne({ _id: 'local' })) + .then(result => { + expect(result).to.have.property('value', 'hello local'); + }); }) - ); - }); + .then(() => { + // #. Call ``client_encryption.encrypt()`` with the value "hello local", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_alt_name`` of ``local_altname``. + // - Expect the return value to be a BSON binary subtype 6. Expect the value to exactly match the value of ``local_encrypted``. + return this.clientEncryption + .encrypt('hello local', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: localDatakeyId + }) + .then(encrypted => { + expect(encrypted).to.deep.equal(localEncrypted); + }); + }); + }); - afterEach(function () { - if (this.commandStartedEvents) { - this.commandStartedEvents.teardown(); - this.commandStartedEvents = undefined; - } - return Promise.resolve() - .then(() => this.clientEncrypted && this.clientEncrypted.close()) - .then(() => this.client && this.client.close()); - }); + it('should work for aws KMS provider', metadata, function () { + // Then, repeat the above tests with the ``aws`` KMS provider: + let awsDatakeyId; + let awsEncrypted; + return Promise.resolve() + .then(() => { + // #. Call ``client_encryption.createDataKey()`` with the ``aws`` KMS provider, keyAltNames set to ``["aws_altname"]``, and ``masterKey`` as follows: + // .. code:: javascript + // { + // region: "us-east-1", + // key: "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" + // } + // - Expect a BSON binary with subtype 4 to be returned, referred to as ``aws_datakey_id``. + // - Use ``client`` to run a ``find`` on ``keyvault.datakeys`` by querying with the ``_id`` set to the ``aws_datakey_id``. + // - Expect that exactly one document is returned with the "masterKey.provider" equal to "aws". + // - Check that ``client`` captured a command_started event for the ``insert`` command containing a majority writeConcern. + this.commandStartedEvents.clear(); + const masterKey = { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0' + }; + return this.clientEncryption + .createDataKey('aws', { masterKey, keyAltNames: ['aws_altname'] }) + .then(result => { + awsDatakeyId = result; + expect(awsDatakeyId).to.have.property('sub_type', 4); + }) + .then(() => { + return this.client + .db(keyVaultDbName) + .collection(keyVaultCollName) + .find({ _id: awsDatakeyId }) + .toArray(); + }) + .then(results => { + expect(results) + .to.have.a.lengthOf(1) + .and.to.have.nested.property('0.masterKey.provider', 'aws'); + expect(this.commandStartedEvents.events).to.containSubset([ + { commandName: 'insert', command: { writeConcern: { w: 'majority' } } } + ]); + }); + }) + .then(() => { + // #. Call ``client_encryption.encrypt()`` with the value "hello aws", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_id`` of ``aws_datakey_id``. + // - Expect the return value to be a BSON binary subtype 6, referred to as ``aws_encrypted``. + // - Use ``client_encrypted`` to insert ``{ _id: "aws", "value": }`` into ``db.coll``. + // - Use ``client_encrypted`` to run a find querying with ``_id`` of "aws" and expect ``value`` to be "hello aws". + const coll = this.clientEncrypted.db(dataDbName).collection(dataCollName); + return this.clientEncryption + .encrypt('hello aws', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: awsDatakeyId + }) + .then(value => { + awsEncrypted = value; + expect(awsEncrypted).to.have.property('sub_type', 6); + }) + .then(() => coll.insertOne({ _id: 'aws', value: awsEncrypted })) + .then(() => coll.findOne({ _id: 'aws' })) + .then(result => { + expect(result).to.have.property('value', 'hello aws'); + }); + }) + .then(() => { + // #. Call ``client_encryption.encrypt()`` with the value "hello aws", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_alt_name`` of ``aws_altname``. + // - Expect the return value to be a BSON binary subtype 6. Expect the value to exactly match the value of ``aws_encrypted``. + return this.clientEncryption + .encrypt('hello aws', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: awsDatakeyId + }) + .then(encrypted => { + expect(encrypted).to.deep.equal(awsEncrypted); + }); + }); + }); - it('should work for local KMS provider', metadata, function () { - let localDatakeyId; - let localEncrypted; - return Promise.resolve() - .then(() => { - // #. Call ``client_encryption.createDataKey()`` with the ``local`` KMS provider and keyAltNames set to ``["local_altname"]``. - // - Expect a BSON binary with subtype 4 to be returned, referred to as ``local_datakey_id``. - // - Use ``client`` to run a ``find`` on ``keyvault.datakeys`` by querying with the ``_id`` set to the ``local_datakey_id``. - // - Expect that exactly one document is returned with the "masterKey.provider" equal to "local". - // - Check that ``client`` captured a command_started event for the ``insert`` command containing a majority writeConcern. - this.commandStartedEvents.clear(); - return this.clientEncryption - .createDataKey('local', { keyAltNames: ['local_altname'] }) - .then(result => { - localDatakeyId = result; - expect(localDatakeyId).to.have.property('sub_type', 4); - }) - .then(() => { - return this.client - .db(keyVaultDbName) - .collection(keyVaultCollName) - .find({ _id: localDatakeyId }) - .toArray(); - }) - .then(results => { - expect(results) - .to.have.a.lengthOf(1) - .and.to.have.nested.property('0.masterKey.provider', 'local'); - expect(this.commandStartedEvents.events).to.containSubset([ - { commandName: 'insert', command: { writeConcern: { w: 'majority' } } } - ]); - }); - }) - .then(() => { - // #. Call ``client_encryption.encrypt()`` with the value "hello local", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_id`` of ``local_datakey_id``. - // - Expect the return value to be a BSON binary subtype 6, referred to as ``local_encrypted``. - // - Use ``client_encrypted`` to insert ``{ _id: "local", "value": }`` into ``db.coll``. - // - Use ``client_encrypted`` to run a find querying with ``_id`` of "local" and expect ``value`` to be "hello local". - const coll = this.clientEncrypted.db(dataDbName).collection(dataCollName); - return this.clientEncryption - .encrypt('hello local', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: localDatakeyId - }) - .then(value => { - localEncrypted = value; - expect(localEncrypted).to.have.property('sub_type', 6); - }) - .then(() => coll.insertOne({ _id: 'local', value: localEncrypted })) - .then(() => coll.findOne({ _id: 'local' })) - .then(result => { - expect(result).to.have.property('value', 'hello local'); - }); - }) - .then(() => { - // #. Call ``client_encryption.encrypt()`` with the value "hello local", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_alt_name`` of ``local_altname``. - // - Expect the return value to be a BSON binary subtype 6. Expect the value to exactly match the value of ``local_encrypted``. - return this.clientEncryption - .encrypt('hello local', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: localDatakeyId + it('should error on an attempt to double-encrypt a value', metadata, function () { + // Then, run the following final tests: + // #. Test explicit encrypting an auto encrypted field. + // - Use ``client_encrypted`` to attempt to insert ``{ "encrypted_placeholder": (local_encrypted) }`` + // - Expect an exception to be thrown, since this is an attempt to auto encrypt an already encrypted value. + return Promise.resolve() + .then(() => this.clientEncryption.createDataKey('local')) + .then(keyId => + this.clientEncryption.encrypt('hello double', { + keyId, + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' }) - .then(encrypted => { - expect(encrypted).to.deep.equal(localEncrypted); - }); - }); - }); - - it('should work for aws KMS provider', metadata, function () { - // Then, repeat the above tests with the ``aws`` KMS provider: - let awsDatakeyId; - let awsEncrypted; - return Promise.resolve() - .then(() => { - // #. Call ``client_encryption.createDataKey()`` with the ``aws`` KMS provider, keyAltNames set to ``["aws_altname"]``, and ``masterKey`` as follows: - // .. code:: javascript - // { - // region: "us-east-1", - // key: "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" - // } - // - Expect a BSON binary with subtype 4 to be returned, referred to as ``aws_datakey_id``. - // - Use ``client`` to run a ``find`` on ``keyvault.datakeys`` by querying with the ``_id`` set to the ``aws_datakey_id``. - // - Expect that exactly one document is returned with the "masterKey.provider" equal to "aws". - // - Check that ``client`` captured a command_started event for the ``insert`` command containing a majority writeConcern. - this.commandStartedEvents.clear(); - const masterKey = { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0' - }; - return this.clientEncryption - .createDataKey('aws', { masterKey, keyAltNames: ['aws_altname'] }) - .then(result => { - awsDatakeyId = result; - expect(awsDatakeyId).to.have.property('sub_type', 4); - }) - .then(() => { - return this.client - .db(keyVaultDbName) - .collection(keyVaultCollName) - .find({ _id: awsDatakeyId }) - .toArray(); - }) - .then(results => { - expect(results) - .to.have.a.lengthOf(1) - .and.to.have.nested.property('0.masterKey.provider', 'aws'); - expect(this.commandStartedEvents.events).to.containSubset([ - { commandName: 'insert', command: { writeConcern: { w: 'majority' } } } - ]); - }); - }) - .then(() => { - // #. Call ``client_encryption.encrypt()`` with the value "hello aws", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_id`` of ``aws_datakey_id``. - // - Expect the return value to be a BSON binary subtype 6, referred to as ``aws_encrypted``. - // - Use ``client_encrypted`` to insert ``{ _id: "aws", "value": }`` into ``db.coll``. - // - Use ``client_encrypted`` to run a find querying with ``_id`` of "aws" and expect ``value`` to be "hello aws". - const coll = this.clientEncrypted.db(dataDbName).collection(dataCollName); - return this.clientEncryption - .encrypt('hello aws', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: awsDatakeyId - }) - .then(value => { - awsEncrypted = value; - expect(awsEncrypted).to.have.property('sub_type', 6); - }) - .then(() => coll.insertOne({ _id: 'aws', value: awsEncrypted })) - .then(() => coll.findOne({ _id: 'aws' })) - .then(result => { - expect(result).to.have.property('value', 'hello aws'); - }); - }) - .then(() => { - // #. Call ``client_encryption.encrypt()`` with the value "hello aws", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_alt_name`` of ``aws_altname``. - // - Expect the return value to be a BSON binary subtype 6. Expect the value to exactly match the value of ``aws_encrypted``. - return this.clientEncryption - .encrypt('hello aws', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: awsDatakeyId - }) - .then(encrypted => { - expect(encrypted).to.deep.equal(awsEncrypted); - }); - }); - }); - - it('should error on an attempt to double-encrypt a value', metadata, function () { - // Then, run the following final tests: - // #. Test explicit encrypting an auto encrypted field. - // - Use ``client_encrypted`` to attempt to insert ``{ "encrypted_placeholder": (local_encrypted) }`` - // - Expect an exception to be thrown, since this is an attempt to auto encrypt an already encrypted value. - return Promise.resolve() - .then(() => this.clientEncryption.createDataKey('local')) - .then(keyId => - this.clientEncryption.encrypt('hello double', { - keyId, - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' - }) - ) - .then(encrypted => - this.clientEncrypted - .db(dataDbName) - .collection(dataCollName) - .insertOne({ encrypted_placeholder: encrypted }) - .then( - () => { - throw new Error('Expected double-encryption to fail, but it has succeeded'); - }, - err => { - expect(err).to.be.an.instanceOf(Error); - } - ) - ); + ) + .then(encrypted => + this.clientEncrypted + .db(dataDbName) + .collection(dataCollName) + .insertOne({ encrypted_placeholder: encrypted }) + .then( + () => { + throw new Error('Expected double-encryption to fail, but it has succeeded'); + }, + err => { + expect(err).to.be.an.instanceOf(Error); + } + ) + ); + }); }); - }); - - describe('Custom Endpoint', function () { - // Data keys created with AWS KMS may specify a custom endpoint to contact (instead of the default endpoint derived from the AWS region). - - beforeEach(function () { - // 1. Create a ``ClientEncryption`` object (referred to as ``client_encryption``) - // Configure with ``aws`` KMS providers as follows: - // .. code:: javascript - // { - // "aws": { } - // } - // Configure with ``keyVaultNamespace`` set to ``keyvault.datakeys``, and a default MongoClient as the ``keyVaultClient``. - this.client = this.configuration.newClient(); - - const customKmsProviders = getKmsProviders(); - customKmsProviders.azure.identityPlatformEndpoint = 'login.microsoftonline.com:443'; - customKmsProviders.gcp.endpoint = 'oauth2.googleapis.com:443'; - - const invalidKmsProviders = getKmsProviders(); - invalidKmsProviders.azure.identityPlatformEndpoint = 'example.com:443'; - invalidKmsProviders.gcp.endpoint = 'example.com:443'; - return this.client.connect().then(() => { - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { - bson: BSON, - keyVaultNamespace, - kmsProviders: customKmsProviders - }); + describe('Custom Endpoint', function () { + // Data keys created with AWS KMS may specify a custom endpoint to contact (instead of the default endpoint derived from the AWS region). + + beforeEach(function () { + // 1. Create a ``ClientEncryption`` object (referred to as ``client_encryption``) + // Configure with ``aws`` KMS providers as follows: + // .. code:: javascript + // { + // "aws": { } + // } + // Configure with ``keyVaultNamespace`` set to ``keyvault.datakeys``, and a default MongoClient as the ``keyVaultClient``. + this.client = this.configuration.newClient(); + + const customKmsProviders = getKmsProviders(); + customKmsProviders.azure.identityPlatformEndpoint = 'login.microsoftonline.com:443'; + customKmsProviders.gcp.endpoint = 'oauth2.googleapis.com:443'; + + const invalidKmsProviders = getKmsProviders(); + invalidKmsProviders.azure.identityPlatformEndpoint = 'example.com:443'; + invalidKmsProviders.gcp.endpoint = 'example.com:443'; + + return this.client.connect().then(() => { + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { + bson: BSON, + keyVaultNamespace, + kmsProviders: customKmsProviders + }); - this.clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(this.client, { - keyVaultNamespace, - kmsProviders: invalidKmsProviders + this.clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(this.client, { + keyVaultNamespace, + kmsProviders: invalidKmsProviders + }); }); }); - }); - afterEach(function () { - return this.client && this.client.close(); - }); + afterEach(function () { + return this.client && this.client.close(); + }); - const testCases = [ - { - description: 'no custom endpoint', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0' - }, - succeed: true - }, - { - description: 'custom endpoint', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'kms.us-east-1.amazonaws.com' + const testCases = [ + { + description: 'no custom endpoint', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0' + }, + succeed: true }, - succeed: true - }, - { - description: 'custom endpoint with port', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'kms.us-east-1.amazonaws.com:443' + { + description: 'custom endpoint', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: 'kms.us-east-1.amazonaws.com' + }, + succeed: true }, - succeed: true - }, - { - description: 'custom endpoint with bad url', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'kms.us-east-1.amazonaws.com:12345' + { + description: 'custom endpoint with port', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: 'kms.us-east-1.amazonaws.com:443' + }, + succeed: true }, - succeed: false, - errorValidator: err => { - expect(err) - .to.be.an.instanceOf(Error) - .and.to.have.property('message') - .that.matches(/KMS request failed/); - } - }, - { - description: 'custom endpoint that does not match region', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'kms.us-east-2.amazonaws.com' + { + description: 'custom endpoint with bad url', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: 'kms.us-east-1.amazonaws.com:12345' + }, + succeed: false, + errorValidator: err => { + expect(err) + .to.be.an.instanceOf(Error) + .and.to.have.property('message') + .that.matches(/KMS request failed/); + } }, - succeed: false, - errorValidator: err => { - // Expect this to fail with an exception with a message containing the string: "us-east-1" - expect(err) - .to.be.an.instanceOf(Error) - .and.to.have.property('message') - .that.matches(/us-east-1/); - } - }, - { - description: 'custom endpoint with parse error', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'example.com' + { + description: 'custom endpoint that does not match region', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: 'kms.us-east-2.amazonaws.com' + }, + succeed: false, + errorValidator: err => { + // Expect this to fail with an exception with a message containing the string: "us-east-1" + expect(err) + .to.be.an.instanceOf(Error) + .and.to.have.property('message') + .that.matches(/us-east-1/); + } }, - succeed: false, - errorValidator: err => { - // Expect this to fail with an exception with a message containing the string: "parse error" - expect(err) - .to.be.an.instanceOf(Error) - .and.to.have.property('message') - .that.matches(/parse error/); - } - }, - { - description: 'azure custom endpoint', - provider: 'azure', - masterKey: { - keyVaultEndpoint: 'key-vault-csfle.vault.azure.net', - keyName: 'key-name-csfle' + { + description: 'custom endpoint with parse error', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: 'example.com' + }, + succeed: false, + errorValidator: err => { + // Expect this to fail with an exception with a message containing the string: "parse error" + expect(err) + .to.be.an.instanceOf(Error) + .and.to.have.property('message') + .that.matches(/parse error/); + } }, - succeed: true, - checkAgainstInvalid: true - }, - { - description: 'gcp custom endpoint', - provider: 'gcp', - masterKey: { - projectId: 'devprod-drivers', - location: 'global', - keyRing: 'key-ring-csfle', - keyName: 'key-name-csfle', - endpoint: 'cloudkms.googleapis.com:443' + { + description: 'azure custom endpoint', + provider: 'azure', + masterKey: { + keyVaultEndpoint: 'key-vault-csfle.vault.azure.net', + keyName: 'key-name-csfle' + }, + succeed: true, + checkAgainstInvalid: true }, - succeed: true, - checkAgainstInvalid: true - }, - { - description: 'gcp invalid custom endpoint', - provider: 'gcp', - masterKey: { - projectId: 'devprod-drivers', - location: 'global', - keyRing: 'key-ring-csfle', - keyName: 'key-name-csfle', - endpoint: 'example.com:443' + { + description: 'gcp custom endpoint', + provider: 'gcp', + masterKey: { + projectId: 'devprod-drivers', + location: 'global', + keyRing: 'key-ring-csfle', + keyName: 'key-name-csfle', + endpoint: 'cloudkms.googleapis.com:443' + }, + succeed: true, + checkAgainstInvalid: true }, - succeed: false, - errorValidator: err => { - // Expect this to fail with an exception with a message containing the string: "parse error" - expect(err) - .to.be.an.instanceOf(Error) - .and.to.have.property('message') - .that.matches(/Invalid KMS response/); + { + description: 'gcp invalid custom endpoint', + provider: 'gcp', + masterKey: { + projectId: 'devprod-drivers', + location: 'global', + keyRing: 'key-ring-csfle', + keyName: 'key-name-csfle', + endpoint: 'example.com:443' + }, + succeed: false, + errorValidator: err => { + // Expect this to fail with an exception with a message containing the string: "parse error" + expect(err) + .to.be.an.instanceOf(Error) + .and.to.have.property('message') + .that.matches(/Invalid KMS response/); + } } - } - ]; - - testCases.forEach(testCase => { - it(testCase.description, metadata, function () { - // 2. Call `client_encryption.createDataKey()` with "aws" as the provider and the following masterKey: - // .. code:: javascript - // { - // ... - // } - // Expect this to succeed. Use the returned UUID of the key to explicitly encrypt and decrypt the string "test" to validate it works. - const masterKey = testCase.masterKey; - - const promises = []; - promises.push( - this.clientEncryption.createDataKey(testCase.provider, { masterKey }).then( - keyId => { - if (!testCase.succeed) { - throw new Error('Expected test case to fail to create data key, but it succeeded'); - } - return this.clientEncryption - .encrypt('test', { - keyId, - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' - }) - .then(encrypted => this.clientEncryption.decrypt(encrypted)) - .then(result => { - expect(result).to.equal('test'); - }); - }, - err => { - if (testCase.succeed) { - throw err; - } - if (!testCase.errorValidator) { - throw new Error('Invalid Error validator'); - } - - testCase.errorValidator(err); - } - ) - ); - - if (testCase.checkAgainstInvalid) { + ]; + + testCases.forEach(testCase => { + it(testCase.description, metadata, function () { + // 2. Call `client_encryption.createDataKey()` with "aws" as the provider and the following masterKey: + // .. code:: javascript + // { + // ... + // } + // Expect this to succeed. Use the returned UUID of the key to explicitly encrypt and decrypt the string "test" to validate it works. + const masterKey = testCase.masterKey; + + const promises = []; promises.push( - this.clientEncryptionInvalid.createDataKey(testCase.provider, { masterKey }).then( - () => { - throw new Error('Expected test case to fail to create data key, but it succeeded'); + this.clientEncryption.createDataKey(testCase.provider, { masterKey }).then( + keyId => { + if (!testCase.succeed) { + throw new Error('Expected test case to fail to create data key, but it succeeded'); + } + return this.clientEncryption + .encrypt('test', { + keyId, + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' + }) + .then(encrypted => this.clientEncryption.decrypt(encrypted)) + .then(result => { + expect(result).to.equal('test'); + }); }, err => { - expect(err) - .property('message') - .to.match(/parse error/); + if (testCase.succeed) { + throw err; + } + if (!testCase.errorValidator) { + throw new Error('Invalid Error validator'); + } + + testCase.errorValidator(err); } ) ); - } - - return Promise.all(promises); - }); - }); - }); - - describe('BSON size limits and batch splitting', function () { - const fs = require('fs'); - const path = require('path'); - const { EJSON } = BSON; - function loadLimits(file) { - return EJSON.parse( - fs.readFileSync(path.resolve(__dirname, '../../spec/client-side-encryption/limits', file)) - ); - } - - const limitsSchema = loadLimits('limits-schema.json'); - const limitsKey = loadLimits('limits-key.json'); - const limitsDoc = loadLimits('limits-doc.json'); - - let hasRunFirstTimeSetup = false; - beforeEach(async function () { - if (hasRunFirstTimeSetup) { - // Even though we have to use a beforeEach here - // We still only want the following code to be run *once* - // before all the tests that follow - return; - } - hasRunFirstTimeSetup = true; - // First, perform the setup. - - // #. Create a MongoClient without encryption enabled (referred to as ``client``). - this.client = this.configuration.newClient(); - - await this.client - .connect() - // #. Using ``client``, drop and create the collection ``db.coll`` configured with the included JSON schema `limits/limits-schema.json <../limits/limits-schema.json>`_. - .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) - .then(() => { - return this.client.db(dataDbName).createCollection(dataCollName, { - validator: { $jsonSchema: limitsSchema } - }); - }) - // #. Using ``client``, drop the collection ``keyvault.datakeys``. Insert the document `limits/limits-key.json <../limits/limits-key.json>`_ - .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) - .then(() => { - return this.client - .db(keyVaultDbName) - .collection(keyVaultCollName) - .insertOne(limitsKey, { writeConcern: { w: 'majority' } }); - }); - }); - beforeEach(function () { - // #. Create a MongoClient configured with auto encryption (referred to as ``client_encrypted``) - // Configure with the ``local`` KMS provider as follows: - // .. code:: javascript - // { "local": { "key": } } - // Configure with the ``keyVaultNamespace`` set to ``keyvault.datakeys``. - this.clientEncrypted = this.configuration.newClient( - {}, - { - monitorCommands: true, - autoEncryption: { - keyVaultNamespace, - kmsProviders: getKmsProviders(LOCAL_KEY) + if (testCase.checkAgainstInvalid) { + promises.push( + this.clientEncryptionInvalid.createDataKey(testCase.provider, { masterKey }).then( + () => { + throw new Error('Expected test case to fail to create data key, but it succeeded'); + }, + err => { + expect(err) + .property('message') + .to.match(/parse error/); + } + ) + ); } - } - ); - return this.clientEncrypted.connect().then(() => { - this.encryptedColl = this.clientEncrypted.db(dataDbName).collection(dataCollName); - this.commandStartedEvents = new APMEventCollector(this.clientEncrypted, 'commandStarted', { - include: ['insert'] + + return Promise.all(promises); }); }); }); - afterEach(function () { - if (this.commandStartedEvents) { - this.commandStartedEvents.teardown(); - this.commandStartedEvents = undefined; - } - if (this.clientEncrypted) { - return this.clientEncrypted.close(); + describe('BSON size limits and batch splitting', function () { + const fs = require('fs'); + const path = require('path'); + const { EJSON } = BSON; + function loadLimits(file) { + return EJSON.parse( + fs.readFileSync(path.resolve(__dirname, '../../spec/client-side-encryption/limits', file)) + ); } - }); - after(function () { - return this.client && this.client.close(); - }); + const limitsSchema = loadLimits('limits-schema.json'); + const limitsKey = loadLimits('limits-key.json'); + const limitsDoc = loadLimits('limits-doc.json'); + + let hasRunFirstTimeSetup = false; + beforeEach(async function () { + if (hasRunFirstTimeSetup) { + // Even though we have to use a beforeEach here + // We still only want the following code to be run *once* + // before all the tests that follow + return; + } + hasRunFirstTimeSetup = true; + // First, perform the setup. - // Using ``client_encrypted`` perform the following operations: - - function repeatedChar(char, length) { - return Array.from({ length }) - .map(() => char) - .join(''); - } - - const testCases = [ - // #. Insert ``{ "_id": "over_2mib_under_16mib", "unencrypted": }``. - // Expect this to succeed since this is still under the ``maxBsonObjectSize`` limit. - { - description: 'should succeed for over_2mib_under_16mib', - docs: () => [{ _id: 'over_2mib_under_16mib', unencrypted: repeatedChar('a', 2097152) }], - expectedEvents: [{ commandName: 'insert' }] - }, - // #. 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 > }`` - // Note: limits-doc.json is a 1005 byte BSON document that encrypts to a ~10,000 byte document. - // Expect this to succeed since after encryption this still is below the normal maximum BSON document size. - // 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. - { - description: 'should succeed for encryption_exceeds_2mib', - docs: () => [ - Object.assign({}, limitsDoc, { - _id: 'encryption_exceeds_2mib', - unencrypted: repeatedChar('a', 2097152 - 2000) - }) - ], - expectedEvents: [{ commandName: 'insert' }] - }, - // #. Bulk insert the following: - // - ``{ "_id": "over_2mib_1", "unencrypted": }`` - // - ``{ "_id": "over_2mib_2", "unencrypted": }`` - // Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). This may be verified using `command monitoring `_. - { - description: 'should succeed for bulk over_2mib', - docs: () => [ - { _id: 'over_2mib_1', unencrypted: repeatedChar('a', 2097152) }, - { _id: 'over_2mib_2', unencrypted: repeatedChar('a', 2097152) } - ], - expectedEvents: [{ commandName: 'insert' }, { commandName: 'insert' }] - }, - // #. Bulk insert the following: - // - 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 > }`` - // - 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 > }`` - // Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). This may be verified using `command monitoring `_. - { - description: 'should succeed for bulk encryption_exceeds_2mib', - docs: () => [ - Object.assign({}, limitsDoc, { - _id: 'encryption_exceeds_2mib_1', - unencrypted: repeatedChar('a', 2097152 - 2000) - }), - Object.assign({}, limitsDoc, { - _id: 'encryption_exceeds_2mib_2', - unencrypted: repeatedChar('a', 2097152 - 2000) - }) - ], - expectedEvents: [{ commandName: 'insert' }, { commandName: 'insert' }] - }, - // #. Insert ``{ "_id": "under_16mib", "unencrypted": ``. - // Expect this to succeed since this is still (just) under the ``maxBsonObjectSize`` limit. - { - description: 'should succeed for under_16mib', - docs: () => [{ _id: 'under_16mib', unencrypted: repeatedChar('a', 16777216 - 2000) }], - expectedEvents: [{ commandName: 'insert' }] - }, - // #. Insert the document `limits/limits-doc.json <../limits/limits-doc.json>`_ concatenated with ``{ "_id": "encryption_exceeds_16mib", "unencrypted": < the string "a" repeated (16777216 - 2000) times > }`` - // Expect this to fail since encryption results in a document exceeding the ``maxBsonObjectSize`` limit. - { - description: 'should fail for encryption_exceeds_16mib', - docs: () => [ - Object.assign({}, limitsDoc, { - _id: 'encryption_exceeds_16mib', - unencrypted: repeatedChar('a', 16777216 - 2000) + // #. Create a MongoClient without encryption enabled (referred to as ``client``). + this.client = this.configuration.newClient(); + + await this.client + .connect() + // #. Using ``client``, drop and create the collection ``db.coll`` configured with the included JSON schema `limits/limits-schema.json <../limits/limits-schema.json>`_. + .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) + .then(() => { + return this.client.db(dataDbName).createCollection(dataCollName, { + validator: { $jsonSchema: limitsSchema } + }); }) - ], - error: true - } - ]; - - testCases.forEach(testCase => { - it(testCase.description, metadata, function () { - return this.encryptedColl.insertMany(testCase.docs()).then( - () => { - if (testCase.error) { - throw new Error('Expected this insert to fail, but it succeeded'); - } - const expectedEvents = Array.from(testCase.expectedEvents); - const actualEvents = pruneEvents(this.commandStartedEvents.events); + // #. Using ``client``, drop the collection ``keyvault.datakeys``. Insert the document `limits/limits-key.json <../limits/limits-key.json>`_ + .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) + .then(() => { + return this.client + .db(keyVaultDbName) + .collection(keyVaultCollName) + .insertOne(limitsKey, { writeConcern: { w: 'majority' } }); + }); + }); - expect(actualEvents) - .to.have.a.lengthOf(expectedEvents.length) - .and.to.containSubset(expectedEvents); - }, - err => { - if (!testCase.error) { - throw err; + beforeEach(function () { + // #. Create a MongoClient configured with auto encryption (referred to as ``client_encrypted``) + // Configure with the ``local`` KMS provider as follows: + // .. code:: javascript + // { "local": { "key": } } + // Configure with the ``keyVaultNamespace`` set to ``keyvault.datakeys``. + this.clientEncrypted = this.configuration.newClient( + {}, + { + monitorCommands: true, + autoEncryption: { + keyVaultNamespace, + kmsProviders: getKmsProviders(LOCAL_KEY) } } ); + return this.clientEncrypted.connect().then(() => { + this.encryptedColl = this.clientEncrypted.db(dataDbName).collection(dataCollName); + this.commandStartedEvents = new APMEventCollector(this.clientEncrypted, 'commandStarted', { + include: ['insert'] + }); + }); }); - }); - function pruneEvents(events) { - return events.map(event => { - // We are pruning out the bunch of repeating As, mostly - // b/c an error failure will try to print 2mb of 'a's - // and not have a good time. - event.command = Object.assign({}, event.command); - event.command.documents = event.command.documents.map(doc => { - doc = Object.assign({}, doc); - if (doc.unencrypted) { - doc.unencrypted = "Lots of repeating 'a's"; - } - return doc; - }); - return event; + afterEach(function () { + if (this.commandStartedEvents) { + this.commandStartedEvents.teardown(); + this.commandStartedEvents = undefined; + } + if (this.clientEncrypted) { + return this.clientEncrypted.close(); + } }); - } - }); - describe('Views are prohibited', function () { - before(function () { - // First, perform the setup. + after(function () { + return this.client && this.client.close(); + }); - // #. Create a MongoClient without encryption enabled (referred to as ``client``). - this.client = this.configuration.newClient(); - - return this.client - .connect() - .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) - .then(() => { - return this.client.db(dataDbName).createCollection(dataCollName); - }) - .then(() => { - return this.client - .db(dataDbName) - .createCollection('view', { viewOn: dataCollName, pipeline: [] }) - .then(noop, noop); - }, noop); - }); + // Using ``client_encrypted`` perform the following operations: - after(function () { - return this.client && this.client.close(); - }); + function repeatedChar(char, length) { + return Array.from({ length }) + .map(() => char) + .join(''); + } - beforeEach(function () { - this.clientEncrypted = this.configuration.newClient( - {}, + const testCases = [ + // #. Insert ``{ "_id": "over_2mib_under_16mib", "unencrypted": }``. + // Expect this to succeed since this is still under the ``maxBsonObjectSize`` limit. { - autoEncryption: { - keyVaultNamespace, - kmsProviders: getKmsProviders(LOCAL_KEY) - } + description: 'should succeed for over_2mib_under_16mib', + docs: () => [{ _id: 'over_2mib_under_16mib', unencrypted: repeatedChar('a', 2097152) }], + expectedEvents: [{ commandName: 'insert' }] + }, + // #. 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 > }`` + // Note: limits-doc.json is a 1005 byte BSON document that encrypts to a ~10,000 byte document. + // Expect this to succeed since after encryption this still is below the normal maximum BSON document size. + // 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. + { + description: 'should succeed for encryption_exceeds_2mib', + docs: () => [ + Object.assign({}, limitsDoc, { + _id: 'encryption_exceeds_2mib', + unencrypted: repeatedChar('a', 2097152 - 2000) + }) + ], + expectedEvents: [{ commandName: 'insert' }] + }, + // #. Bulk insert the following: + // - ``{ "_id": "over_2mib_1", "unencrypted": }`` + // - ``{ "_id": "over_2mib_2", "unencrypted": }`` + // Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). This may be verified using `command monitoring `_. + { + description: 'should succeed for bulk over_2mib', + docs: () => [ + { _id: 'over_2mib_1', unencrypted: repeatedChar('a', 2097152) }, + { _id: 'over_2mib_2', unencrypted: repeatedChar('a', 2097152) } + ], + expectedEvents: [{ commandName: 'insert' }, { commandName: 'insert' }] + }, + // #. Bulk insert the following: + // - 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 > }`` + // - 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 > }`` + // Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). This may be verified using `command monitoring `_. + { + description: 'should succeed for bulk encryption_exceeds_2mib', + docs: () => [ + Object.assign({}, limitsDoc, { + _id: 'encryption_exceeds_2mib_1', + unencrypted: repeatedChar('a', 2097152 - 2000) + }), + Object.assign({}, limitsDoc, { + _id: 'encryption_exceeds_2mib_2', + unencrypted: repeatedChar('a', 2097152 - 2000) + }) + ], + expectedEvents: [{ commandName: 'insert' }, { commandName: 'insert' }] + }, + // #. Insert ``{ "_id": "under_16mib", "unencrypted": ``. + // Expect this to succeed since this is still (just) under the ``maxBsonObjectSize`` limit. + { + description: 'should succeed for under_16mib', + docs: () => [{ _id: 'under_16mib', unencrypted: repeatedChar('a', 16777216 - 2000) }], + expectedEvents: [{ commandName: 'insert' }] + }, + // #. Insert the document `limits/limits-doc.json <../limits/limits-doc.json>`_ concatenated with ``{ "_id": "encryption_exceeds_16mib", "unencrypted": < the string "a" repeated (16777216 - 2000) times > }`` + // Expect this to fail since encryption results in a document exceeding the ``maxBsonObjectSize`` limit. + { + description: 'should fail for encryption_exceeds_16mib', + docs: () => [ + Object.assign({}, limitsDoc, { + _id: 'encryption_exceeds_16mib', + unencrypted: repeatedChar('a', 16777216 - 2000) + }) + ], + error: true } - ); + ]; + + testCases.forEach(testCase => { + it(testCase.description, metadata, function () { + return this.encryptedColl.insertMany(testCase.docs()).then( + () => { + if (testCase.error) { + throw new Error('Expected this insert to fail, but it succeeded'); + } + const expectedEvents = Array.from(testCase.expectedEvents); + const actualEvents = pruneEvents(this.commandStartedEvents.events); - return this.clientEncrypted.connect(); - }); + expect(actualEvents) + .to.have.a.lengthOf(expectedEvents.length) + .and.to.containSubset(expectedEvents); + }, + err => { + if (!testCase.error) { + throw err; + } + } + ); + }); + }); - afterEach(function () { - return this.clientEncrypted && this.clientEncrypted.close(); + function pruneEvents(events) { + return events.map(event => { + // We are pruning out the bunch of repeating As, mostly + // b/c an error failure will try to print 2mb of 'a's + // and not have a good time. + event.command = Object.assign({}, event.command); + event.command.documents = event.command.documents.map(doc => { + doc = Object.assign({}, doc); + if (doc.unencrypted) { + doc.unencrypted = "Lots of repeating 'a's"; + } + return doc; + }); + return event; + }); + } }); - it('should error when inserting into a view with autoEncryption', metadata, function () { - return this.clientEncrypted - .db(dataDbName) - .collection('view') - .insertOne({ a: 1 }) - .then( - () => { - throw new Error('Expected insert to fail, but it succeeded'); - }, - err => { - expect(err) - .to.have.property('message') - .that.matches(/cannot auto encrypt a view/); - } - ); - }); - }); + describe('Views are prohibited', function () { + before(function () { + // First, perform the setup. + + // #. Create a MongoClient without encryption enabled (referred to as ``client``). + this.client = this.configuration.newClient(); - // TODO: We cannot implement these tests according to spec b/c the tests require a - // connect-less client. So instead we are implementing the tests via APM, - // and confirming that the externalClient is firing off keyVault requests during - // encrypted operations - describe('External Key Vault', function () { - const fs = require('fs'); - const path = require('path'); - const { EJSON } = BSON; - function loadExternal(file) { - return EJSON.parse( - fs.readFileSync(path.resolve(__dirname, '../../spec/client-side-encryption/external', file)) - ); - } - - const externalKey = loadExternal('external-key.json'); - const externalSchema = loadExternal('external-schema.json'); - - beforeEach(function () { - this.client = this.configuration.newClient(); - - // #. Create a MongoClient without encryption enabled (referred to as ``client``). - return ( - this.client + return this.client .connect() - // #. Using ``client``, drop the collections ``keyvault.datakeys`` and ``db.coll``. - // Insert the document `external/external-key.json <../external/external-key.json>`_ into ``keyvault.datakeys``. .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) - .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) .then(() => { - return this.client - .db(keyVaultDbName) - .collection(keyVaultCollName) - .insertOne(externalKey, { writeConcern: { w: 'majority' } }); + return this.client.db(dataDbName).createCollection(dataCollName); }) - ); + .then(() => { + return this.client + .db(dataDbName) + .createCollection('view', { viewOn: dataCollName, pipeline: [] }) + .then(noop, noop); + }, noop); + }); + + after(function () { + return this.client && this.client.close(); + }); + + beforeEach(function () { + this.clientEncrypted = this.configuration.newClient( + {}, + { + autoEncryption: { + keyVaultNamespace, + kmsProviders: getKmsProviders(LOCAL_KEY) + } + } + ); + + return this.clientEncrypted.connect(); + }); + + afterEach(function () { + return this.clientEncrypted && this.clientEncrypted.close(); + }); + + it('should error when inserting into a view with autoEncryption', metadata, function () { + return this.clientEncrypted + .db(dataDbName) + .collection('view') + .insertOne({ a: 1 }) + .then( + () => { + throw new Error('Expected insert to fail, but it succeeded'); + }, + err => { + expect(err) + .to.have.property('message') + .that.matches(/cannot auto encrypt a view/); + } + ); + }); }); - afterEach(function () { - if (this.commandStartedEvents) { - this.commandStartedEvents.teardown(); - this.commandStartedEvents = undefined; + // TODO: We cannot implement these tests according to spec b/c the tests require a + // connect-less client. So instead we are implementing the tests via APM, + // and confirming that the externalClient is firing off keyVault requests during + // encrypted operations + describe('External Key Vault', function () { + const fs = require('fs'); + const path = require('path'); + const { EJSON } = BSON; + function loadExternal(file) { + return EJSON.parse( + fs.readFileSync(path.resolve(__dirname, '../../spec/client-side-encryption/external', file)) + ); } - return Promise.resolve() - .then(() => this.externalClient && this.externalClient.close()) - .then(() => this.clientEncrypted && this.clientEncrypted.close()) - .then(() => this.client && this.client.close()); - }); - function defineTest(withExternalKeyVault) { - it( - `should work ${withExternalKeyVault ? 'with' : 'without'} external key vault`, - metadata, - function () { - const ClientEncryption = this.configuration.mongodbClientEncryption.ClientEncryption; - return ( - Promise.resolve() - .then(() => { - // If ``withExternalKeyVault == true``, configure both objects with an external key vault client. The external client MUST connect to the same - // MongoDB cluster that is being tested against, except it MUST use the username ``fake-user`` and password ``fake-pwd``. - this.externalClient = this.configuration.newClient( - // this.configuration.url('fake-user', 'fake-pwd'), - // TODO: Do this properly - {}, - { monitorCommands: true } - ); - - this.commandStartedEvents = new APMEventCollector( - this.externalClient, - 'commandStarted', - { - include: ['find'] - } - ); - return this.externalClient.connect(); - }) - // #. Create the following: - // - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) - // - A ``ClientEncryption`` object (referred to as ``client_encryption``) - // Configure both objects with the ``local`` KMS providers as follows: - // .. code:: javascript - // { "local": { "key": } } - // Configure both objects with ``keyVaultNamespace`` set to ``keyvault.datakeys``. - // 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": }`` - .then(() => { - const options = { - bson: BSON, - keyVaultNamespace, - kmsProviders: getKmsProviders(LOCAL_KEY) - }; - - if (withExternalKeyVault) { - options.keyVaultClient = this.externalClient; - } + const externalKey = loadExternal('external-key.json'); + const externalSchema = loadExternal('external-schema.json'); - this.clientEncryption = new ClientEncryption( - this.client, - Object.assign({}, options) - ); - this.clientEncrypted = this.configuration.newClient( - {}, - { - autoEncryption: Object.assign({}, options, { - schemaMap: { - 'db.coll': externalSchema - } - }) - } - ); - return this.clientEncrypted.connect(); - }) - .then(() => { - // #. Use ``client_encrypted`` to insert the document ``{"encrypted": "test"}`` into ``db.coll``. - // If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed. - this.commandStartedEvents.clear(); - return this.clientEncrypted - .db(dataDbName) - .collection(dataCollName) - .insertOne({ encrypted: 'test' }) - .then(() => { - if (withExternalKeyVault) { - expect(this.commandStartedEvents.events).to.containSubset([ - { - commandName: 'find', - databaseName: keyVaultDbName, - command: { find: keyVaultCollName } - } - ]); - } else { - expect(this.commandStartedEvents.events).to.not.containSubset([ - { - commandName: 'find', - databaseName: keyVaultDbName, - command: { find: keyVaultCollName } - } - ]); + beforeEach(function () { + this.client = this.configuration.newClient(); + + // #. Create a MongoClient without encryption enabled (referred to as ``client``). + return ( + this.client + .connect() + // #. Using ``client``, drop the collections ``keyvault.datakeys`` and ``db.coll``. + // Insert the document `external/external-key.json <../external/external-key.json>`_ into ``keyvault.datakeys``. + .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) + .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) + .then(() => { + return this.client + .db(keyVaultDbName) + .collection(keyVaultCollName) + .insertOne(externalKey, { writeConcern: { w: 'majority' } }); + }) + ); + }); + + afterEach(function () { + if (this.commandStartedEvents) { + this.commandStartedEvents.teardown(); + this.commandStartedEvents = undefined; + } + return Promise.resolve() + .then(() => this.externalClient && this.externalClient.close()) + .then(() => this.clientEncrypted && this.clientEncrypted.close()) + .then(() => this.client && this.client.close()); + }); + + function defineTest(withExternalKeyVault) { + it( + `should work ${withExternalKeyVault ? 'with' : 'without'} external key vault`, + metadata, + function () { + const ClientEncryption = this.configuration.mongodbClientEncryption.ClientEncryption; + return ( + Promise.resolve() + .then(() => { + // If ``withExternalKeyVault == true``, configure both objects with an external key vault client. The external client MUST connect to the same + // MongoDB cluster that is being tested against, except it MUST use the username ``fake-user`` and password ``fake-pwd``. + this.externalClient = this.configuration.newClient( + // this.configuration.url('fake-user', 'fake-pwd'), + // TODO: Do this properly + {}, + { monitorCommands: true } + ); + + this.commandStartedEvents = new APMEventCollector( + this.externalClient, + 'commandStarted', + { + include: ['find'] } - }); - // TODO: Do this in the spec-compliant way using bad auth credentials - // .then( - // () => { - // if (withExternalKeyVault) { - // throw new Error( - // 'expected insert to fail with authentication error, but it passed' - // ); - // } - // }, - // err => { - // if (!withExternalKeyVault) { - // throw err; - // } - // expect(err).to.be.an.instanceOf(Error); - // } - // ); - }) - .then(() => { - // #. Use ``client_encryption`` to explicitly encrypt the string ``"test"`` with key ID ``LOCALAAAAAAAAAAAAAAAAA==`` and deterministic algorithm. - // If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed. - this.commandStartedEvents.clear(); - return this.clientEncryption - .encrypt('test', { - keyId: externalKey._id, - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' - }) - .then(() => { - if (withExternalKeyVault) { - expect(this.commandStartedEvents.events).to.containSubset([ - { - commandName: 'find', - databaseName: keyVaultDbName, - command: { find: keyVaultCollName } - } - ]); - } else { - expect(this.commandStartedEvents.events).to.not.containSubset([ - { - commandName: 'find', - databaseName: keyVaultDbName, - command: { find: keyVaultCollName } + ); + return this.externalClient.connect(); + }) + // #. Create the following: + // - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) + // - A ``ClientEncryption`` object (referred to as ``client_encryption``) + // Configure both objects with the ``local`` KMS providers as follows: + // .. code:: javascript + // { "local": { "key": } } + // Configure both objects with ``keyVaultNamespace`` set to ``keyvault.datakeys``. + // 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": }`` + .then(() => { + const options = { + bson: BSON, + keyVaultNamespace, + kmsProviders: getKmsProviders(LOCAL_KEY) + }; + + if (withExternalKeyVault) { + options.keyVaultClient = this.externalClient; + } + + this.clientEncryption = new ClientEncryption( + this.client, + Object.assign({}, options) + ); + this.clientEncrypted = this.configuration.newClient( + {}, + { + autoEncryption: Object.assign({}, options, { + schemaMap: { + 'db.coll': externalSchema } - ]); + }) } - }); - // TODO: Do this in the spec-compliant way using bad auth credentials - // .then( - // () => { - // if (withExternalKeyVault) { - // throw new Error( - // 'expected insert to fail with authentication error, but it passed' - // ); - // } - // }, - // err => { - // if (!withExternalKeyVault) { - // throw err; - // } - // expect(err).to.be.an.instanceOf(Error); - // } - // ); - }) - ); - } - ); - } - // Run the following tests twice, parameterized by a boolean ``withExternalKeyVault``. - defineTest(true); - defineTest(false); - }); + ); + return this.clientEncrypted.connect(); + }) + .then(() => { + // #. Use ``client_encrypted`` to insert the document ``{"encrypted": "test"}`` into ``db.coll``. + // If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed. + this.commandStartedEvents.clear(); + return this.clientEncrypted + .db(dataDbName) + .collection(dataCollName) + .insertOne({ encrypted: 'test' }) + .then(() => { + if (withExternalKeyVault) { + expect(this.commandStartedEvents.events).to.containSubset([ + { + commandName: 'find', + databaseName: keyVaultDbName, + command: { find: keyVaultCollName } + } + ]); + } else { + expect(this.commandStartedEvents.events).to.not.containSubset([ + { + commandName: 'find', + databaseName: keyVaultDbName, + command: { find: keyVaultCollName } + } + ]); + } + }); + // TODO: Do this in the spec-compliant way using bad auth credentials + // .then( + // () => { + // if (withExternalKeyVault) { + // throw new Error( + // 'expected insert to fail with authentication error, but it passed' + // ); + // } + // }, + // err => { + // if (!withExternalKeyVault) { + // throw err; + // } + // expect(err).to.be.an.instanceOf(Error); + // } + // ); + }) + .then(() => { + // #. Use ``client_encryption`` to explicitly encrypt the string ``"test"`` with key ID ``LOCALAAAAAAAAAAAAAAAAA==`` and deterministic algorithm. + // If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed. + this.commandStartedEvents.clear(); + return this.clientEncryption + .encrypt('test', { + keyId: externalKey._id, + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' + }) + .then(() => { + if (withExternalKeyVault) { + expect(this.commandStartedEvents.events).to.containSubset([ + { + commandName: 'find', + databaseName: keyVaultDbName, + command: { find: keyVaultCollName } + } + ]); + } else { + expect(this.commandStartedEvents.events).to.not.containSubset([ + { + commandName: 'find', + databaseName: keyVaultDbName, + command: { find: keyVaultCollName } + } + ]); + } + }); + // TODO: Do this in the spec-compliant way using bad auth credentials + // .then( + // () => { + // if (withExternalKeyVault) { + // throw new Error( + // 'expected insert to fail with authentication error, but it passed' + // ); + // } + // }, + // err => { + // if (!withExternalKeyVault) { + // throw err; + // } + // expect(err).to.be.an.instanceOf(Error); + // } + // ); + }) + ); + } + ); + } + // Run the following tests twice, parameterized by a boolean ``withExternalKeyVault``. + defineTest(true); + defineTest(false); + }); - deadlockTests(metadata); -}); + deadlockTests(metadata); + }); +} From 3240c7472658ec2f8f5b809ae524731f33810c06 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Fri, 4 Feb 2022 11:11:32 +0100 Subject: [PATCH 47/73] test(NODE-3777): fix lint errors --- .../client_side_encryption.prose.test.js | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 99a40a11320..b6ff4ad0ca1 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -921,7 +921,9 @@ if (!process.env.LOAD_BALANCER) { this.clientEncryption.createDataKey(testCase.provider, { masterKey }).then( keyId => { if (!testCase.succeed) { - throw new Error('Expected test case to fail to create data key, but it succeeded'); + throw new Error( + 'Expected test case to fail to create data key, but it succeeded' + ); } return this.clientEncryption .encrypt('test', { @@ -950,7 +952,9 @@ if (!process.env.LOAD_BALANCER) { promises.push( this.clientEncryptionInvalid.createDataKey(testCase.provider, { masterKey }).then( () => { - throw new Error('Expected test case to fail to create data key, but it succeeded'); + throw new Error( + 'Expected test case to fail to create data key, but it succeeded' + ); }, err => { expect(err) @@ -1031,9 +1035,13 @@ if (!process.env.LOAD_BALANCER) { ); return this.clientEncrypted.connect().then(() => { this.encryptedColl = this.clientEncrypted.db(dataDbName).collection(dataCollName); - this.commandStartedEvents = new APMEventCollector(this.clientEncrypted, 'commandStarted', { - include: ['insert'] - }); + this.commandStartedEvents = new APMEventCollector( + this.clientEncrypted, + 'commandStarted', + { + include: ['insert'] + } + ); }); }); @@ -1244,7 +1252,9 @@ if (!process.env.LOAD_BALANCER) { const { EJSON } = BSON; function loadExternal(file) { return EJSON.parse( - fs.readFileSync(path.resolve(__dirname, '../../spec/client-side-encryption/external', file)) + fs.readFileSync( + path.resolve(__dirname, '../../spec/client-side-encryption/external', file) + ) ); } From 5fe9e7a0e76c75330e5e3015dee4fea5fac23466 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 12:59:19 +0100 Subject: [PATCH 48/73] test(NODE-3777): use subprocess to start kms servers --- .evergreen/config.yml | 3 ++- .evergreen/config.yml.in | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 19b217679e6..14e5e361ca1 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -108,12 +108,13 @@ functions: cd ${DRIVERS_TOOLS}/.evergreen/csfle . ./activate_venv.sh fi - - command: shell.exec + - command: subprocess.exec params: background: true script: | if [ -n "${CLIENT_ENCRYPTION}" ]; then cd ${DRIVERS_TOOLS}/.evergreen/csfle + # by default it always runs on port 5698 ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index cf3bab336fd..8ceaf2ed58f 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -128,12 +128,13 @@ functions: cd ${DRIVERS_TOOLS}/.evergreen/csfle . ./activate_venv.sh fi - - command: shell.exec + - command: subprocess.exec params: background: true script: | if [ -n "${CLIENT_ENCRYPTION}" ]; then cd ${DRIVERS_TOOLS}/.evergreen/csfle + # by default it always runs on port 5698 ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & From bb42ed80d5444978865458c290beb90702f9ab7e Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 13:01:54 +0100 Subject: [PATCH 49/73] test(NODE-3777): add kmip docs to test readme --- test/readme.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/readme.md b/test/readme.md index bd7b6f86a52..b5105234b90 100644 --- a/test/readme.md +++ b/test/readme.md @@ -347,6 +347,23 @@ The following steps will walk you through how to run the tests for CSFLE. The output of the tests will include sections like "Client Side Encryption Corpus," "Client Side Encryption Functional," "Client Side Encryption Prose Tests," and "Client Side Encryption." +#### KMIP FLE support tests + +1. Install virtualenv: `pip install virtualenv` +2. Source the ./activate_venv.sh script in driver evergreen tools `.evergreen/csfle/activate_venv.sh` + 1. This will install all the dependencies needed to run a python kms_kmip simulated server +3. In 4 separate terminals launch the following: + - `./kmstlsvenv/bin/python3 -u kms_kmip_server.py` # by default it always runs on port 5698 + - `./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000` + - `./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001` + - `./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert` +4. Set the following environment variables: + - `export KMIP_TLS_CA_FILE="${DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem"` + - `export KMIP_TLS_CERT_FILE="${DRIVERS_TOOLS}/.evergreen/x509gen/client.pem"` +5. Install the FLE lib: `npm i --no-save mongodb-client-encryption` +6. Launch a mongodb server +7. Run the full suite `npm run check:test` or more specifically `npx mocha --config test/mocha_mongodb.json test/integration/client-side-encryption/` + ### TODO Special Env Sections - Kerberos From 04290ae4f311e395cc7a97afe1bb33cd02270db6 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 13:06:44 +0100 Subject: [PATCH 50/73] test(NODE-3777): skip before blocks in lb mode --- .../client_side_encryption.prose.test.js | 2514 +++++++++-------- 1 file changed, 1259 insertions(+), 1255 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index b6ff4ad0ca1..3bee277da02 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -44,80 +44,121 @@ const metadata = { // Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk // TODO: NODE-3927 - these cannot run in lb mode but are not skipping based on metadata. -if (!process.env.LOAD_BALANCER) { - describe('Client Side Encryption Prose Tests', metadata, function () { - const dataDbName = 'db'; - const dataCollName = 'coll'; - const dataNamespace = `${dataDbName}.${dataCollName}`; - const keyVaultDbName = 'keyvault'; - const keyVaultCollName = 'datakeys'; - const keyVaultNamespace = `${keyVaultDbName}.${keyVaultCollName}`; - - const shared = require('../shared'); - const dropCollection = shared.dropCollection; - const APMEventCollector = shared.APMEventCollector; - - const LOCAL_KEY = Buffer.from( - 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk', - 'base64' - ); - - context('when kmip is the kms provider', metadata, async function () { - const autoEncryptionOptions = { - keyVaultNamespace, +describe('Client Side Encryption Prose Tests', metadata, function () { + const dataDbName = 'db'; + const dataCollName = 'coll'; + const dataNamespace = `${dataDbName}.${dataCollName}`; + const keyVaultDbName = 'keyvault'; + const keyVaultCollName = 'datakeys'; + const keyVaultNamespace = `${keyVaultDbName}.${keyVaultCollName}`; + + const shared = require('../shared'); + const dropCollection = shared.dropCollection; + const APMEventCollector = shared.APMEventCollector; + + const LOCAL_KEY = Buffer.from( + 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk', + 'base64' + ); + + context('when kmip is the kms provider', metadata, async function () { + const autoEncryptionOptions = { + keyVaultNamespace, + kmsProviders: { + kmip: { + endpoint: 'localhost:5698' + } + }, + tlsOptions: { + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } + }; + let client; + let clientEncryption; + let clientEncryptionInvalid; + + before(async function () { + if (process.env.LOAD_BALANCER) this.skip(); + client = this.configuration.newClient(); + await client.connect(); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + clientEncryption = new mongodbClientEncryption.ClientEncryption(client, { + ...autoEncryptionOptions, + bson: BSON + }); + clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(client, { + ...autoEncryptionOptions, + bson: BSON, kmsProviders: { kmip: { - endpoint: 'localhost:5698' - } - }, - tlsOptions: { - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + endpoint: 'invalid.localhost:5698' } } - }; - let client; - let clientEncryption; - let clientEncryptionInvalid; + }); + await dropCollection(client.db(keyVaultDbName), keyVaultCollName); + await dropCollection(client.db(keyVaultDbName), keyVaultCollName); + }); - before(async function () { - client = this.configuration.newClient(); - await client.connect(); - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - clientEncryption = new mongodbClientEncryption.ClientEncryption(client, { - ...autoEncryptionOptions, - bson: BSON + after(async function () { + if (process.env.LOAD_BALANCER) this.skip(); + await client.close(); + }); + + context('when encrypting with kmip', metadata, async function () { + context('when not providing an endpoint in the master key', metadata, async function () { + const masterKey = { keyId: '1' }; + let dataKey; + let encrypted; + let decrypted; + + /** + * 10. + * - Create data key with kmip as provider and master key of { keyId: '1' } + * - Use UUID to encrypt and decrypt to value. + * - Create data key with invalid encrypter and expect failure. + */ + before(async function () { + if (process.env.LOAD_BALANCER) this.skip(); + dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); + encrypted = await clientEncryption.encrypt('test', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: dataKey + }); + decrypted = await clientEncryption.decrypt(encrypted); }); - clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(client, { - ...autoEncryptionOptions, - bson: BSON, - kmsProviders: { - kmip: { - endpoint: 'invalid.localhost:5698' - } - } + + it('must create a data key', metadata, function () { + expect(dataKey).to.have.property('sub_type', 4); + }); + + it('properly encrypts and decrypts', metadata, function () { + expect(decrypted).to.equal('test'); }); - await dropCollection(client.db(keyVaultDbName), keyVaultCollName); - await dropCollection(client.db(keyVaultDbName), keyVaultCollName); - }); - after(async function () { - await client.close(); + it('fails with invalid provider host', metadata, async function () { + try { + await clientEncryptionInvalid.createDataKey('kmip', { masterKey }); + } catch (e) { + expect(e.message).to.equal('KMS request failed'); + } + }); }); - context('when encrypting with kmip', metadata, async function () { - context('when not providing an endpoint in the master key', metadata, async function () { - const masterKey = { keyId: '1' }; + context('when providing an endpoint in the master key', metadata, function () { + context('when the endpoint is valid', metadata, function () { + const masterKey = { keyId: '1', endpoint: 'localhost:5698' }; let dataKey; let encrypted; let decrypted; /** - * 10. - * - Create data key with kmip as provider and master key of { keyId: '1' } + * 11. + * - Create data key with kmip as provider and master key of + * { keyId: 1, endpoint: 'localhost:5698 '} * - Use UUID to encrypt and decrypt to value. - * - Create data key with invalid encrypter and expect failure. */ before(async function () { dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); @@ -135,1323 +176,1286 @@ if (!process.env.LOAD_BALANCER) { it('properly encrypts and decrypts', metadata, function () { expect(decrypted).to.equal('test'); }); + }); + context('when the endpoint is invalid', metadata, function () { + const masterKey = { keyId: '1', endpoint: 'doesnotexist.localhost:5698' }; + + /** + * 12. + * - Create data key with kmip as provider and master key of + * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} + * - Expect failure. + */ it('fails with invalid provider host', metadata, async function () { try { - await clientEncryptionInvalid.createDataKey('kmip', { masterKey }); + await clientEncryption.createDataKey('kmip', { masterKey }); } catch (e) { expect(e.message).to.equal('KMS request failed'); } }); }); - - context('when providing an endpoint in the master key', metadata, function () { - context('when the endpoint is valid', metadata, function () { - const masterKey = { keyId: '1', endpoint: 'localhost:5698' }; - let dataKey; - let encrypted; - let decrypted; - - /** - * 11. - * - Create data key with kmip as provider and master key of - * { keyId: 1, endpoint: 'localhost:5698 '} - * - Use UUID to encrypt and decrypt to value. - */ - before(async function () { - dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); - encrypted = await clientEncryption.encrypt('test', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: dataKey - }); - decrypted = await clientEncryption.decrypt(encrypted); - }); - - it('must create a data key', metadata, function () { - expect(dataKey).to.have.property('sub_type', 4); - }); - - it('properly encrypts and decrypts', metadata, function () { - expect(decrypted).to.equal('test'); - }); - }); - - context('when the endpoint is invalid', metadata, function () { - const masterKey = { keyId: '1', endpoint: 'doesnotexist.localhost:5698' }; - - /** - * 12. - * - Create data key with kmip as provider and master key of - * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} - * - Expect failure. - */ - it('fails with invalid provider host', metadata, async function () { - try { - await clientEncryption.createDataKey('kmip', { masterKey }); - } catch (e) { - expect(e.message).to.equal('KMS request failed'); - } - }); - }); - }); }); }); + }); - /** - * - Create client encryption no tls - * - Create client encryption with tls - * - Create client encryption expired - * - Create client encryption invalid hostname - */ - context('when passing through tls options', metadata, async function () { - let tlsCaOptions; - let clientNoTlsOptions; - let clientWithTlsOptions; - let clientWithTlsExpiredOptions; - let clientWithInvalidHostnameOptions; - let clientNoTls; - let clientWithTls; - let clientWithTlsExpired; - let clientWithInvalidHostname; - let clientEncryptionNoTls; - let clientEncryptionWithTls; - let clientEncryptionWithTlsExpired; - let clientEncryptionWithInvalidHostname; - - before(async function () { - tlsCaOptions = { + /** + * - Create client encryption no tls + * - Create client encryption with tls + * - Create client encryption expired + * - Create client encryption invalid hostname + */ + context('when passing through tls options', metadata, async function () { + let tlsCaOptions; + let clientNoTlsOptions; + let clientWithTlsOptions; + let clientWithTlsExpiredOptions; + let clientWithInvalidHostnameOptions; + let clientNoTls; + let clientWithTls; + let clientWithTlsExpired; + let clientWithInvalidHostname; + let clientEncryptionNoTls; + let clientEncryptionWithTls; + let clientEncryptionWithTlsExpired; + let clientEncryptionWithInvalidHostname; + + before(async function () { + if (process.env.LOAD_BALANCER) this.skip(); + tlsCaOptions = { + aws: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + azure: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + gcp: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + }, + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE + } + }; + clientNoTlsOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), + tlsOptions: tlsCaOptions + }; + clientWithTlsOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), + tlsOptions: { aws: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE }, azure: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE }, gcp: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE }, kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE } + } + }; + clientWithTlsExpiredOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, '127.0.0.1:8000', '127.0.0.1:8000', '127.0.0.1:8000'), + tlsOptions: tlsCaOptions + }; + clientWithInvalidHostnameOptions = { + keyVaultNamespace, + kmsProviders: getKmsProviders(null, '127.0.0.1:8001', '127.0.0.1:8001', '127.0.0.1:8001'), + tlsOptions: tlsCaOptions + }; + clientNoTls = this.configuration.newClient({}, { autoEncryption: clientNoTlsOptions }); + clientWithTls = this.configuration.newClient({}, { autoEncryption: clientWithTlsOptions }); + clientWithTlsExpired = this.configuration.newClient( + {}, + { autoEncryption: clientWithTlsExpiredOptions } + ); + clientWithInvalidHostname = this.configuration.newClient( + {}, + { autoEncryption: clientWithInvalidHostnameOptions } + ); + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { + ...clientNoTlsOptions, + bson: BSON + }); + clientEncryptionWithTls = new mongodbClientEncryption.ClientEncryption(clientWithTls, { + ...clientWithTlsOptions, + bson: BSON + }); + clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( + clientWithTlsExpired, + { ...clientWithTlsExpiredOptions, bson: BSON } + ); + clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( + clientWithInvalidHostname, + { ...clientWithInvalidHostnameOptions, bson: BSON } + ); + }); + + context('when using tls clients', metadata, function () { + beforeEach('connecting tls clients', async function () { + if (process.env.LOAD_BALANCER) this.skip(); + await clientNoTls.connect(); + await clientWithTls.connect(); + await clientWithTlsExpired.connect(); + await clientWithInvalidHostname.connect(); + await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); + await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); + }); + + afterEach(async function () { + if (process.env.LOAD_BALANCER) this.skip(); + await clientNoTls.close(); + await clientWithTls.close(); + await clientWithTlsExpired.close(); + await clientWithInvalidHostname.close(); + }); + + // Case 1. + context('when using aws', metadata, function () { + const masterKey = { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: '127.0.0.1:8002' }; - clientNoTlsOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), - tlsOptions: tlsCaOptions - }; - clientWithTlsOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, null, '127.0.0.1:8002', '127.0.0.1:8002'), - tlsOptions: { - aws: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - }, - azure: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - }, - gcp: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - }, - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - } + const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; + const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; + + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('aws', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); } - }; - clientWithTlsExpiredOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, '127.0.0.1:8000', '127.0.0.1:8000', '127.0.0.1:8000'), - tlsOptions: tlsCaOptions - }; - clientWithInvalidHostnameOptions = { - keyVaultNamespace, - kmsProviders: getKmsProviders(null, '127.0.0.1:8001', '127.0.0.1:8001', '127.0.0.1:8001'), - tlsOptions: tlsCaOptions - }; - clientNoTls = this.configuration.newClient({}, { autoEncryption: clientNoTlsOptions }); - clientWithTls = this.configuration.newClient({}, { autoEncryption: clientWithTlsOptions }); - clientWithTlsExpired = this.configuration.newClient( - {}, - { autoEncryption: clientWithTlsExpiredOptions } - ); - clientWithInvalidHostname = this.configuration.newClient( - {}, - { autoEncryption: clientWithInvalidHostnameOptions } - ); - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - clientEncryptionNoTls = new mongodbClientEncryption.ClientEncryption(clientNoTls, { - ...clientNoTlsOptions, - bson: BSON }); - clientEncryptionWithTls = new mongodbClientEncryption.ClientEncryption(clientWithTls, { - ...clientWithTlsOptions, - bson: BSON - }); - clientEncryptionWithTlsExpired = new mongodbClientEncryption.ClientEncryption( - clientWithTlsExpired, - { ...clientWithTlsExpiredOptions, bson: BSON } - ); - clientEncryptionWithInvalidHostname = new mongodbClientEncryption.ClientEncryption( - clientWithInvalidHostname, - { ...clientWithInvalidHostnameOptions, bson: BSON } - ); - }); - context('when using tls clients', metadata, function () { - beforeEach('connecting tls clients', async function () { - await clientNoTls.connect(); - await clientWithTls.connect(); - await clientWithTlsExpired.connect(); - await clientWithInvalidHostname.connect(); - await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); - await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); + it('passes with tls but fails to parse', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('aws', { masterKey }); + } catch (e) { + expect(e.message).to.include('parse error'); + } }); - afterEach(async function () { - await clientNoTls.close(); - await clientWithTls.close(); - await clientWithTlsExpired.close(); - await clientWithInvalidHostname.close(); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); + } catch (e) { + expect(e.message).to.include('expected UTF-8 key'); + } }); - // Case 1. - context('when using aws', metadata, function () { - const masterKey = { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: '127.0.0.1:8002' - }; - const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; - const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; - - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('aws', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } - }); - - it('passes with tls but fails to parse', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('aws', { masterKey }); - } catch (e) { - expect(e.message).to.include('parse error'); - } - }); - - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); - } catch (e) { - expect(e.message).to.include('expected UTF-8 key'); - } - }); - - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('aws', { - masterKeyInvalidHostname - }); - } catch (e) { - expect(e.message).to.include('expected UTF-8 key'); - } - }); + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('aws', { + masterKeyInvalidHostname + }); + } catch (e) { + expect(e.message).to.include('expected UTF-8 key'); + } }); + }); - // Case 2. - context('when using azure', metadata, function () { - const masterKey = { - keyVaultEndpoint: 'doesnotexist.local', - keyName: 'foo' - }; + // Case 2. + context('when using azure', metadata, function () { + const masterKey = { + keyVaultEndpoint: 'doesnotexist.local', + keyName: 'foo' + }; - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } - }); + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } + }); - it('fails with invalid host', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.message).to.include('HTTP status=404'); - } - }); + it('fails with invalid host', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.message).to.include('HTTP status=404'); + } + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } - }); + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } }); + }); - // Case 3. - context('when using gcp', metadata, function () { - const masterKey = { - projectId: 'foo', - location: 'bar', - keyRing: 'baz', - keyName: 'foo' - }; + // Case 3. + context('when using gcp', metadata, function () { + const masterKey = { + projectId: 'foo', + location: 'bar', + keyRing: 'baz', + keyName: 'foo' + }; - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } - }); + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } + }); - it('fails with invalid host', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.message).to.include('HTTP status=404'); - } - }); + it('fails with invalid host', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.message).to.include('HTTP status=404'); + } + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } - }); + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } }); + }); - // Case 4. - context('when using kmip', metadata, function () { - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('kmip'); - } catch (e) { - expect(e.originalError.message).to.include('before secure TLS connection'); - } - }); + // Case 4. + context('when using kmip', metadata, function () { + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('kmip'); + } catch (e) { + expect(e.originalError.message).to.include('before secure TLS connection'); + } + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('kmip'); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('kmip'); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('kmip'); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } - }); + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('kmip'); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } }); }); }); + }); - describe('Data key and double encryption', function () { - // Data key and double encryption - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // First, perform the setup. - beforeEach(function () { - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + describe('Data key and double encryption', function () { + // Data key and double encryption + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // First, perform the setup. + beforeEach(function () { + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - // #. Create a MongoClient without encryption enabled (referred to as ``client``). Enable command monitoring to listen for command_started events. - this.client = this.configuration.newClient({}, { monitorCommands: true }); + // #. Create a MongoClient without encryption enabled (referred to as ``client``). Enable command monitoring to listen for command_started events. + this.client = this.configuration.newClient({}, { monitorCommands: true }); - this.commandStartedEvents = new APMEventCollector(this.client, 'commandStarted', { - exclude: [LEGACY_HELLO_COMMAND] - }); + this.commandStartedEvents = new APMEventCollector(this.client, 'commandStarted', { + exclude: [LEGACY_HELLO_COMMAND] + }); - const schemaMap = { - [dataNamespace]: { - bsonType: 'object', - properties: { - encrypted_placeholder: { - encrypt: { - keyId: '/placeholder', - bsonType: 'string', - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Random' - } + const schemaMap = { + [dataNamespace]: { + bsonType: 'object', + properties: { + encrypted_placeholder: { + encrypt: { + keyId: '/placeholder', + bsonType: 'string', + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Random' } } } - }; - - return ( - Promise.resolve() - .then(() => this.client.connect()) - // #. Using ``client``, drop the collections ``keyvault.datakeys`` and ``db.coll``. - .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) - .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) - // #. Create the following: - // - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) - // - A ``ClientEncryption`` object (referred to as ``client_encryption``) - // Configure both objects with ``aws`` and the ``local`` KMS providers as follows: - // .. code:: javascript - // { - // "aws": { }, - // "local": { "key": } - // } - // Configure both objects with ``keyVaultNamespace`` set to ``keyvault.datakeys``. - // Configure the ``MongoClient`` with the following ``schema_map``: - // .. code:: javascript - // { - // "db.coll": { - // "bsonType": "object", - // "properties": { - // "encrypted_placeholder": { - // "encrypt": { - // "keyId": "/placeholder", - // "bsonType": "string", - // "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" - // } - // } - // } - // } - // } - // Configure ``client_encryption`` with the ``keyVaultClient`` of the previously created ``client``. - .then(() => { - this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { - kmsProviders: getKmsProviders(), - keyVaultNamespace - }); - }) - .then(() => { - this.clientEncrypted = this.configuration.newClient( - {}, - { - autoEncryption: { - keyVaultNamespace, - kmsProviders: getKmsProviders(), - schemaMap - } - } - ); - return this.clientEncrypted.connect(); - }) - ); - }); - - afterEach(function () { - if (this.commandStartedEvents) { - this.commandStartedEvents.teardown(); - this.commandStartedEvents = undefined; } - return Promise.resolve() - .then(() => this.clientEncrypted && this.clientEncrypted.close()) - .then(() => this.client && this.client.close()); - }); - - it('should work for local KMS provider', metadata, function () { - let localDatakeyId; - let localEncrypted; - return Promise.resolve() - .then(() => { - // #. Call ``client_encryption.createDataKey()`` with the ``local`` KMS provider and keyAltNames set to ``["local_altname"]``. - // - Expect a BSON binary with subtype 4 to be returned, referred to as ``local_datakey_id``. - // - Use ``client`` to run a ``find`` on ``keyvault.datakeys`` by querying with the ``_id`` set to the ``local_datakey_id``. - // - Expect that exactly one document is returned with the "masterKey.provider" equal to "local". - // - Check that ``client`` captured a command_started event for the ``insert`` command containing a majority writeConcern. - this.commandStartedEvents.clear(); - return this.clientEncryption - .createDataKey('local', { keyAltNames: ['local_altname'] }) - .then(result => { - localDatakeyId = result; - expect(localDatakeyId).to.have.property('sub_type', 4); - }) - .then(() => { - return this.client - .db(keyVaultDbName) - .collection(keyVaultCollName) - .find({ _id: localDatakeyId }) - .toArray(); - }) - .then(results => { - expect(results) - .to.have.a.lengthOf(1) - .and.to.have.nested.property('0.masterKey.provider', 'local'); - expect(this.commandStartedEvents.events).to.containSubset([ - { commandName: 'insert', command: { writeConcern: { w: 'majority' } } } - ]); - }); - }) - .then(() => { - // #. Call ``client_encryption.encrypt()`` with the value "hello local", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_id`` of ``local_datakey_id``. - // - Expect the return value to be a BSON binary subtype 6, referred to as ``local_encrypted``. - // - Use ``client_encrypted`` to insert ``{ _id: "local", "value": }`` into ``db.coll``. - // - Use ``client_encrypted`` to run a find querying with ``_id`` of "local" and expect ``value`` to be "hello local". - const coll = this.clientEncrypted.db(dataDbName).collection(dataCollName); - return this.clientEncryption - .encrypt('hello local', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: localDatakeyId - }) - .then(value => { - localEncrypted = value; - expect(localEncrypted).to.have.property('sub_type', 6); - }) - .then(() => coll.insertOne({ _id: 'local', value: localEncrypted })) - .then(() => coll.findOne({ _id: 'local' })) - .then(result => { - expect(result).to.have.property('value', 'hello local'); - }); - }) - .then(() => { - // #. Call ``client_encryption.encrypt()`` with the value "hello local", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_alt_name`` of ``local_altname``. - // - Expect the return value to be a BSON binary subtype 6. Expect the value to exactly match the value of ``local_encrypted``. - return this.clientEncryption - .encrypt('hello local', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: localDatakeyId - }) - .then(encrypted => { - expect(encrypted).to.deep.equal(localEncrypted); - }); - }); - }); + }; - it('should work for aws KMS provider', metadata, function () { - // Then, repeat the above tests with the ``aws`` KMS provider: - let awsDatakeyId; - let awsEncrypted; - return Promise.resolve() - .then(() => { - // #. Call ``client_encryption.createDataKey()`` with the ``aws`` KMS provider, keyAltNames set to ``["aws_altname"]``, and ``masterKey`` as follows: - // .. code:: javascript - // { - // region: "us-east-1", - // key: "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" - // } - // - Expect a BSON binary with subtype 4 to be returned, referred to as ``aws_datakey_id``. - // - Use ``client`` to run a ``find`` on ``keyvault.datakeys`` by querying with the ``_id`` set to the ``aws_datakey_id``. - // - Expect that exactly one document is returned with the "masterKey.provider" equal to "aws". - // - Check that ``client`` captured a command_started event for the ``insert`` command containing a majority writeConcern. - this.commandStartedEvents.clear(); - const masterKey = { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0' - }; - return this.clientEncryption - .createDataKey('aws', { masterKey, keyAltNames: ['aws_altname'] }) - .then(result => { - awsDatakeyId = result; - expect(awsDatakeyId).to.have.property('sub_type', 4); - }) - .then(() => { - return this.client - .db(keyVaultDbName) - .collection(keyVaultCollName) - .find({ _id: awsDatakeyId }) - .toArray(); - }) - .then(results => { - expect(results) - .to.have.a.lengthOf(1) - .and.to.have.nested.property('0.masterKey.provider', 'aws'); - expect(this.commandStartedEvents.events).to.containSubset([ - { commandName: 'insert', command: { writeConcern: { w: 'majority' } } } - ]); - }); - }) + return ( + Promise.resolve() + .then(() => this.client.connect()) + // #. Using ``client``, drop the collections ``keyvault.datakeys`` and ``db.coll``. + .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) + .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) + // #. Create the following: + // - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) + // - A ``ClientEncryption`` object (referred to as ``client_encryption``) + // Configure both objects with ``aws`` and the ``local`` KMS providers as follows: + // .. code:: javascript + // { + // "aws": { }, + // "local": { "key": } + // } + // Configure both objects with ``keyVaultNamespace`` set to ``keyvault.datakeys``. + // Configure the ``MongoClient`` with the following ``schema_map``: + // .. code:: javascript + // { + // "db.coll": { + // "bsonType": "object", + // "properties": { + // "encrypted_placeholder": { + // "encrypt": { + // "keyId": "/placeholder", + // "bsonType": "string", + // "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + // } + // } + // } + // } + // } + // Configure ``client_encryption`` with the ``keyVaultClient`` of the previously created ``client``. .then(() => { - // #. Call ``client_encryption.encrypt()`` with the value "hello aws", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_id`` of ``aws_datakey_id``. - // - Expect the return value to be a BSON binary subtype 6, referred to as ``aws_encrypted``. - // - Use ``client_encrypted`` to insert ``{ _id: "aws", "value": }`` into ``db.coll``. - // - Use ``client_encrypted`` to run a find querying with ``_id`` of "aws" and expect ``value`` to be "hello aws". - const coll = this.clientEncrypted.db(dataDbName).collection(dataCollName); - return this.clientEncryption - .encrypt('hello aws', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: awsDatakeyId - }) - .then(value => { - awsEncrypted = value; - expect(awsEncrypted).to.have.property('sub_type', 6); - }) - .then(() => coll.insertOne({ _id: 'aws', value: awsEncrypted })) - .then(() => coll.findOne({ _id: 'aws' })) - .then(result => { - expect(result).to.have.property('value', 'hello aws'); - }); + this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { + kmsProviders: getKmsProviders(), + keyVaultNamespace + }); }) .then(() => { - // #. Call ``client_encryption.encrypt()`` with the value "hello aws", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_alt_name`` of ``aws_altname``. - // - Expect the return value to be a BSON binary subtype 6. Expect the value to exactly match the value of ``aws_encrypted``. - return this.clientEncryption - .encrypt('hello aws', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: awsDatakeyId - }) - .then(encrypted => { - expect(encrypted).to.deep.equal(awsEncrypted); - }); - }); - }); - - it('should error on an attempt to double-encrypt a value', metadata, function () { - // Then, run the following final tests: - // #. Test explicit encrypting an auto encrypted field. - // - Use ``client_encrypted`` to attempt to insert ``{ "encrypted_placeholder": (local_encrypted) }`` - // - Expect an exception to be thrown, since this is an attempt to auto encrypt an already encrypted value. - return Promise.resolve() - .then(() => this.clientEncryption.createDataKey('local')) - .then(keyId => - this.clientEncryption.encrypt('hello double', { - keyId, - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' - }) - ) - .then(encrypted => - this.clientEncrypted - .db(dataDbName) - .collection(dataCollName) - .insertOne({ encrypted_placeholder: encrypted }) - .then( - () => { - throw new Error('Expected double-encryption to fail, but it has succeeded'); - }, - err => { - expect(err).to.be.an.instanceOf(Error); + this.clientEncrypted = this.configuration.newClient( + {}, + { + autoEncryption: { + keyVaultNamespace, + kmsProviders: getKmsProviders(), + schemaMap } - ) - ); - }); + } + ); + return this.clientEncrypted.connect(); + }) + ); }); - describe('Custom Endpoint', function () { - // Data keys created with AWS KMS may specify a custom endpoint to contact (instead of the default endpoint derived from the AWS region). - - beforeEach(function () { - // 1. Create a ``ClientEncryption`` object (referred to as ``client_encryption``) - // Configure with ``aws`` KMS providers as follows: - // .. code:: javascript - // { - // "aws": { } - // } - // Configure with ``keyVaultNamespace`` set to ``keyvault.datakeys``, and a default MongoClient as the ``keyVaultClient``. - this.client = this.configuration.newClient(); - - const customKmsProviders = getKmsProviders(); - customKmsProviders.azure.identityPlatformEndpoint = 'login.microsoftonline.com:443'; - customKmsProviders.gcp.endpoint = 'oauth2.googleapis.com:443'; - - const invalidKmsProviders = getKmsProviders(); - invalidKmsProviders.azure.identityPlatformEndpoint = 'example.com:443'; - invalidKmsProviders.gcp.endpoint = 'example.com:443'; - - return this.client.connect().then(() => { - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { - bson: BSON, - keyVaultNamespace, - kmsProviders: customKmsProviders - }); - - this.clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(this.client, { - keyVaultNamespace, - kmsProviders: invalidKmsProviders - }); - }); - }); + afterEach(function () { + if (this.commandStartedEvents) { + this.commandStartedEvents.teardown(); + this.commandStartedEvents = undefined; + } + return Promise.resolve() + .then(() => this.clientEncrypted && this.clientEncrypted.close()) + .then(() => this.client && this.client.close()); + }); - afterEach(function () { - return this.client && this.client.close(); - }); + it('should work for local KMS provider', metadata, function () { + let localDatakeyId; + let localEncrypted; + return Promise.resolve() + .then(() => { + // #. Call ``client_encryption.createDataKey()`` with the ``local`` KMS provider and keyAltNames set to ``["local_altname"]``. + // - Expect a BSON binary with subtype 4 to be returned, referred to as ``local_datakey_id``. + // - Use ``client`` to run a ``find`` on ``keyvault.datakeys`` by querying with the ``_id`` set to the ``local_datakey_id``. + // - Expect that exactly one document is returned with the "masterKey.provider" equal to "local". + // - Check that ``client`` captured a command_started event for the ``insert`` command containing a majority writeConcern. + this.commandStartedEvents.clear(); + return this.clientEncryption + .createDataKey('local', { keyAltNames: ['local_altname'] }) + .then(result => { + localDatakeyId = result; + expect(localDatakeyId).to.have.property('sub_type', 4); + }) + .then(() => { + return this.client + .db(keyVaultDbName) + .collection(keyVaultCollName) + .find({ _id: localDatakeyId }) + .toArray(); + }) + .then(results => { + expect(results) + .to.have.a.lengthOf(1) + .and.to.have.nested.property('0.masterKey.provider', 'local'); + expect(this.commandStartedEvents.events).to.containSubset([ + { commandName: 'insert', command: { writeConcern: { w: 'majority' } } } + ]); + }); + }) + .then(() => { + // #. Call ``client_encryption.encrypt()`` with the value "hello local", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_id`` of ``local_datakey_id``. + // - Expect the return value to be a BSON binary subtype 6, referred to as ``local_encrypted``. + // - Use ``client_encrypted`` to insert ``{ _id: "local", "value": }`` into ``db.coll``. + // - Use ``client_encrypted`` to run a find querying with ``_id`` of "local" and expect ``value`` to be "hello local". + const coll = this.clientEncrypted.db(dataDbName).collection(dataCollName); + return this.clientEncryption + .encrypt('hello local', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: localDatakeyId + }) + .then(value => { + localEncrypted = value; + expect(localEncrypted).to.have.property('sub_type', 6); + }) + .then(() => coll.insertOne({ _id: 'local', value: localEncrypted })) + .then(() => coll.findOne({ _id: 'local' })) + .then(result => { + expect(result).to.have.property('value', 'hello local'); + }); + }) + .then(() => { + // #. Call ``client_encryption.encrypt()`` with the value "hello local", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_alt_name`` of ``local_altname``. + // - Expect the return value to be a BSON binary subtype 6. Expect the value to exactly match the value of ``local_encrypted``. + return this.clientEncryption + .encrypt('hello local', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: localDatakeyId + }) + .then(encrypted => { + expect(encrypted).to.deep.equal(localEncrypted); + }); + }); + }); - const testCases = [ - { - description: 'no custom endpoint', - provider: 'aws', - masterKey: { + it('should work for aws KMS provider', metadata, function () { + // Then, repeat the above tests with the ``aws`` KMS provider: + let awsDatakeyId; + let awsEncrypted; + return Promise.resolve() + .then(() => { + // #. Call ``client_encryption.createDataKey()`` with the ``aws`` KMS provider, keyAltNames set to ``["aws_altname"]``, and ``masterKey`` as follows: + // .. code:: javascript + // { + // region: "us-east-1", + // key: "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0" + // } + // - Expect a BSON binary with subtype 4 to be returned, referred to as ``aws_datakey_id``. + // - Use ``client`` to run a ``find`` on ``keyvault.datakeys`` by querying with the ``_id`` set to the ``aws_datakey_id``. + // - Expect that exactly one document is returned with the "masterKey.provider" equal to "aws". + // - Check that ``client`` captured a command_started event for the ``insert`` command containing a majority writeConcern. + this.commandStartedEvents.clear(); + const masterKey = { region: 'us-east-1', key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0' - }, - succeed: true - }, - { - description: 'custom endpoint', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'kms.us-east-1.amazonaws.com' - }, - succeed: true - }, - { - description: 'custom endpoint with port', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'kms.us-east-1.amazonaws.com:443' - }, - succeed: true - }, - { - description: 'custom endpoint with bad url', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'kms.us-east-1.amazonaws.com:12345' - }, - succeed: false, - errorValidator: err => { - expect(err) - .to.be.an.instanceOf(Error) - .and.to.have.property('message') - .that.matches(/KMS request failed/); - } - }, - { - description: 'custom endpoint that does not match region', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'kms.us-east-2.amazonaws.com' - }, - succeed: false, - errorValidator: err => { - // Expect this to fail with an exception with a message containing the string: "us-east-1" - expect(err) - .to.be.an.instanceOf(Error) - .and.to.have.property('message') - .that.matches(/us-east-1/); - } - }, - { - description: 'custom endpoint with parse error', - provider: 'aws', - masterKey: { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'example.com' - }, - succeed: false, - errorValidator: err => { - // Expect this to fail with an exception with a message containing the string: "parse error" - expect(err) - .to.be.an.instanceOf(Error) - .and.to.have.property('message') - .that.matches(/parse error/); - } - }, - { - description: 'azure custom endpoint', - provider: 'azure', - masterKey: { - keyVaultEndpoint: 'key-vault-csfle.vault.azure.net', - keyName: 'key-name-csfle' - }, - succeed: true, - checkAgainstInvalid: true - }, - { - description: 'gcp custom endpoint', - provider: 'gcp', - masterKey: { - projectId: 'devprod-drivers', - location: 'global', - keyRing: 'key-ring-csfle', - keyName: 'key-name-csfle', - endpoint: 'cloudkms.googleapis.com:443' - }, - succeed: true, - checkAgainstInvalid: true - }, - { - description: 'gcp invalid custom endpoint', - provider: 'gcp', - masterKey: { - projectId: 'devprod-drivers', - location: 'global', - keyRing: 'key-ring-csfle', - keyName: 'key-name-csfle', - endpoint: 'example.com:443' - }, - succeed: false, - errorValidator: err => { - // Expect this to fail with an exception with a message containing the string: "parse error" - expect(err) - .to.be.an.instanceOf(Error) - .and.to.have.property('message') - .that.matches(/Invalid KMS response/); - } - } - ]; - - testCases.forEach(testCase => { - it(testCase.description, metadata, function () { - // 2. Call `client_encryption.createDataKey()` with "aws" as the provider and the following masterKey: - // .. code:: javascript - // { - // ... - // } - // Expect this to succeed. Use the returned UUID of the key to explicitly encrypt and decrypt the string "test" to validate it works. - const masterKey = testCase.masterKey; - - const promises = []; - promises.push( - this.clientEncryption.createDataKey(testCase.provider, { masterKey }).then( - keyId => { - if (!testCase.succeed) { - throw new Error( - 'Expected test case to fail to create data key, but it succeeded' - ); - } - return this.clientEncryption - .encrypt('test', { - keyId, - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' - }) - .then(encrypted => this.clientEncryption.decrypt(encrypted)) - .then(result => { - expect(result).to.equal('test'); - }); + }; + return this.clientEncryption + .createDataKey('aws', { masterKey, keyAltNames: ['aws_altname'] }) + .then(result => { + awsDatakeyId = result; + expect(awsDatakeyId).to.have.property('sub_type', 4); + }) + .then(() => { + return this.client + .db(keyVaultDbName) + .collection(keyVaultCollName) + .find({ _id: awsDatakeyId }) + .toArray(); + }) + .then(results => { + expect(results) + .to.have.a.lengthOf(1) + .and.to.have.nested.property('0.masterKey.provider', 'aws'); + expect(this.commandStartedEvents.events).to.containSubset([ + { commandName: 'insert', command: { writeConcern: { w: 'majority' } } } + ]); + }); + }) + .then(() => { + // #. Call ``client_encryption.encrypt()`` with the value "hello aws", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_id`` of ``aws_datakey_id``. + // - Expect the return value to be a BSON binary subtype 6, referred to as ``aws_encrypted``. + // - Use ``client_encrypted`` to insert ``{ _id: "aws", "value": }`` into ``db.coll``. + // - Use ``client_encrypted`` to run a find querying with ``_id`` of "aws" and expect ``value`` to be "hello aws". + const coll = this.clientEncrypted.db(dataDbName).collection(dataCollName); + return this.clientEncryption + .encrypt('hello aws', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: awsDatakeyId + }) + .then(value => { + awsEncrypted = value; + expect(awsEncrypted).to.have.property('sub_type', 6); + }) + .then(() => coll.insertOne({ _id: 'aws', value: awsEncrypted })) + .then(() => coll.findOne({ _id: 'aws' })) + .then(result => { + expect(result).to.have.property('value', 'hello aws'); + }); + }) + .then(() => { + // #. Call ``client_encryption.encrypt()`` with the value "hello aws", the algorithm ``AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic``, and the ``key_alt_name`` of ``aws_altname``. + // - Expect the return value to be a BSON binary subtype 6. Expect the value to exactly match the value of ``aws_encrypted``. + return this.clientEncryption + .encrypt('hello aws', { + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', + keyId: awsDatakeyId + }) + .then(encrypted => { + expect(encrypted).to.deep.equal(awsEncrypted); + }); + }); + }); + + it('should error on an attempt to double-encrypt a value', metadata, function () { + // Then, run the following final tests: + // #. Test explicit encrypting an auto encrypted field. + // - Use ``client_encrypted`` to attempt to insert ``{ "encrypted_placeholder": (local_encrypted) }`` + // - Expect an exception to be thrown, since this is an attempt to auto encrypt an already encrypted value. + return Promise.resolve() + .then(() => this.clientEncryption.createDataKey('local')) + .then(keyId => + this.clientEncryption.encrypt('hello double', { + keyId, + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' + }) + ) + .then(encrypted => + this.clientEncrypted + .db(dataDbName) + .collection(dataCollName) + .insertOne({ encrypted_placeholder: encrypted }) + .then( + () => { + throw new Error('Expected double-encryption to fail, but it has succeeded'); }, err => { - if (testCase.succeed) { - throw err; - } - if (!testCase.errorValidator) { - throw new Error('Invalid Error validator'); - } - - testCase.errorValidator(err); + expect(err).to.be.an.instanceOf(Error); } ) - ); - - if (testCase.checkAgainstInvalid) { - promises.push( - this.clientEncryptionInvalid.createDataKey(testCase.provider, { masterKey }).then( - () => { - throw new Error( - 'Expected test case to fail to create data key, but it succeeded' - ); - }, - err => { - expect(err) - .property('message') - .to.match(/parse error/); - } - ) - ); - } - - return Promise.all(promises); - }); - }); + ); }); + }); - describe('BSON size limits and batch splitting', function () { - const fs = require('fs'); - const path = require('path'); - const { EJSON } = BSON; - function loadLimits(file) { - return EJSON.parse( - fs.readFileSync(path.resolve(__dirname, '../../spec/client-side-encryption/limits', file)) - ); - } + describe('Custom Endpoint', function () { + // Data keys created with AWS KMS may specify a custom endpoint to contact (instead of the default endpoint derived from the AWS region). - const limitsSchema = loadLimits('limits-schema.json'); - const limitsKey = loadLimits('limits-key.json'); - const limitsDoc = loadLimits('limits-doc.json'); - - let hasRunFirstTimeSetup = false; - beforeEach(async function () { - if (hasRunFirstTimeSetup) { - // Even though we have to use a beforeEach here - // We still only want the following code to be run *once* - // before all the tests that follow - return; - } - hasRunFirstTimeSetup = true; - // First, perform the setup. + beforeEach(function () { + // 1. Create a ``ClientEncryption`` object (referred to as ``client_encryption``) + // Configure with ``aws`` KMS providers as follows: + // .. code:: javascript + // { + // "aws": { } + // } + // Configure with ``keyVaultNamespace`` set to ``keyvault.datakeys``, and a default MongoClient as the ``keyVaultClient``. + this.client = this.configuration.newClient(); - // #. Create a MongoClient without encryption enabled (referred to as ``client``). - this.client = this.configuration.newClient(); + const customKmsProviders = getKmsProviders(); + customKmsProviders.azure.identityPlatformEndpoint = 'login.microsoftonline.com:443'; + customKmsProviders.gcp.endpoint = 'oauth2.googleapis.com:443'; - await this.client - .connect() - // #. Using ``client``, drop and create the collection ``db.coll`` configured with the included JSON schema `limits/limits-schema.json <../limits/limits-schema.json>`_. - .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) - .then(() => { - return this.client.db(dataDbName).createCollection(dataCollName, { - validator: { $jsonSchema: limitsSchema } - }); - }) - // #. Using ``client``, drop the collection ``keyvault.datakeys``. Insert the document `limits/limits-key.json <../limits/limits-key.json>`_ - .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) - .then(() => { - return this.client - .db(keyVaultDbName) - .collection(keyVaultCollName) - .insertOne(limitsKey, { writeConcern: { w: 'majority' } }); - }); - }); + const invalidKmsProviders = getKmsProviders(); + invalidKmsProviders.azure.identityPlatformEndpoint = 'example.com:443'; + invalidKmsProviders.gcp.endpoint = 'example.com:443'; - beforeEach(function () { - // #. Create a MongoClient configured with auto encryption (referred to as ``client_encrypted``) - // Configure with the ``local`` KMS provider as follows: - // .. code:: javascript - // { "local": { "key": } } - // Configure with the ``keyVaultNamespace`` set to ``keyvault.datakeys``. - this.clientEncrypted = this.configuration.newClient( - {}, - { - monitorCommands: true, - autoEncryption: { - keyVaultNamespace, - kmsProviders: getKmsProviders(LOCAL_KEY) - } - } - ); - return this.clientEncrypted.connect().then(() => { - this.encryptedColl = this.clientEncrypted.db(dataDbName).collection(dataCollName); - this.commandStartedEvents = new APMEventCollector( - this.clientEncrypted, - 'commandStarted', - { - include: ['insert'] - } - ); + return this.client.connect().then(() => { + const mongodbClientEncryption = this.configuration.mongodbClientEncryption; + this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { + bson: BSON, + keyVaultNamespace, + kmsProviders: customKmsProviders }); - }); - - afterEach(function () { - if (this.commandStartedEvents) { - this.commandStartedEvents.teardown(); - this.commandStartedEvents = undefined; - } - if (this.clientEncrypted) { - return this.clientEncrypted.close(); - } - }); - after(function () { - return this.client && this.client.close(); + this.clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(this.client, { + keyVaultNamespace, + kmsProviders: invalidKmsProviders + }); }); + }); - // Using ``client_encrypted`` perform the following operations: - - function repeatedChar(char, length) { - return Array.from({ length }) - .map(() => char) - .join(''); - } + afterEach(function () { + return this.client && this.client.close(); + }); - const testCases = [ - // #. Insert ``{ "_id": "over_2mib_under_16mib", "unencrypted": }``. - // Expect this to succeed since this is still under the ``maxBsonObjectSize`` limit. - { - description: 'should succeed for over_2mib_under_16mib', - docs: () => [{ _id: 'over_2mib_under_16mib', unencrypted: repeatedChar('a', 2097152) }], - expectedEvents: [{ commandName: 'insert' }] + const testCases = [ + { + description: 'no custom endpoint', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0' }, - // #. 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 > }`` - // Note: limits-doc.json is a 1005 byte BSON document that encrypts to a ~10,000 byte document. - // Expect this to succeed since after encryption this still is below the normal maximum BSON document size. - // 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. - { - description: 'should succeed for encryption_exceeds_2mib', - docs: () => [ - Object.assign({}, limitsDoc, { - _id: 'encryption_exceeds_2mib', - unencrypted: repeatedChar('a', 2097152 - 2000) - }) - ], - expectedEvents: [{ commandName: 'insert' }] + succeed: true + }, + { + description: 'custom endpoint', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: 'kms.us-east-1.amazonaws.com' }, - // #. Bulk insert the following: - // - ``{ "_id": "over_2mib_1", "unencrypted": }`` - // - ``{ "_id": "over_2mib_2", "unencrypted": }`` - // Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). This may be verified using `command monitoring `_. - { - description: 'should succeed for bulk over_2mib', - docs: () => [ - { _id: 'over_2mib_1', unencrypted: repeatedChar('a', 2097152) }, - { _id: 'over_2mib_2', unencrypted: repeatedChar('a', 2097152) } - ], - expectedEvents: [{ commandName: 'insert' }, { commandName: 'insert' }] + succeed: true + }, + { + description: 'custom endpoint with port', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: 'kms.us-east-1.amazonaws.com:443' }, - // #. Bulk insert the following: - // - 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 > }`` - // - 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 > }`` - // Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). This may be verified using `command monitoring `_. - { - description: 'should succeed for bulk encryption_exceeds_2mib', - docs: () => [ - Object.assign({}, limitsDoc, { - _id: 'encryption_exceeds_2mib_1', - unencrypted: repeatedChar('a', 2097152 - 2000) - }), - Object.assign({}, limitsDoc, { - _id: 'encryption_exceeds_2mib_2', - unencrypted: repeatedChar('a', 2097152 - 2000) - }) - ], - expectedEvents: [{ commandName: 'insert' }, { commandName: 'insert' }] + succeed: true + }, + { + description: 'custom endpoint with bad url', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: 'kms.us-east-1.amazonaws.com:12345' }, - // #. Insert ``{ "_id": "under_16mib", "unencrypted": ``. - // Expect this to succeed since this is still (just) under the ``maxBsonObjectSize`` limit. - { - description: 'should succeed for under_16mib', - docs: () => [{ _id: 'under_16mib', unencrypted: repeatedChar('a', 16777216 - 2000) }], - expectedEvents: [{ commandName: 'insert' }] + succeed: false, + errorValidator: err => { + expect(err) + .to.be.an.instanceOf(Error) + .and.to.have.property('message') + .that.matches(/KMS request failed/); + } + }, + { + description: 'custom endpoint that does not match region', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: 'kms.us-east-2.amazonaws.com' }, - // #. Insert the document `limits/limits-doc.json <../limits/limits-doc.json>`_ concatenated with ``{ "_id": "encryption_exceeds_16mib", "unencrypted": < the string "a" repeated (16777216 - 2000) times > }`` - // Expect this to fail since encryption results in a document exceeding the ``maxBsonObjectSize`` limit. - { - description: 'should fail for encryption_exceeds_16mib', - docs: () => [ - Object.assign({}, limitsDoc, { - _id: 'encryption_exceeds_16mib', - unencrypted: repeatedChar('a', 16777216 - 2000) - }) - ], - error: true + succeed: false, + errorValidator: err => { + // Expect this to fail with an exception with a message containing the string: "us-east-1" + expect(err) + .to.be.an.instanceOf(Error) + .and.to.have.property('message') + .that.matches(/us-east-1/); + } + }, + { + description: 'custom endpoint with parse error', + provider: 'aws', + masterKey: { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: 'example.com' + }, + succeed: false, + errorValidator: err => { + // Expect this to fail with an exception with a message containing the string: "parse error" + expect(err) + .to.be.an.instanceOf(Error) + .and.to.have.property('message') + .that.matches(/parse error/); } - ]; - - testCases.forEach(testCase => { - it(testCase.description, metadata, function () { - return this.encryptedColl.insertMany(testCase.docs()).then( - () => { - if (testCase.error) { - throw new Error('Expected this insert to fail, but it succeeded'); + }, + { + description: 'azure custom endpoint', + provider: 'azure', + masterKey: { + keyVaultEndpoint: 'key-vault-csfle.vault.azure.net', + keyName: 'key-name-csfle' + }, + succeed: true, + checkAgainstInvalid: true + }, + { + description: 'gcp custom endpoint', + provider: 'gcp', + masterKey: { + projectId: 'devprod-drivers', + location: 'global', + keyRing: 'key-ring-csfle', + keyName: 'key-name-csfle', + endpoint: 'cloudkms.googleapis.com:443' + }, + succeed: true, + checkAgainstInvalid: true + }, + { + description: 'gcp invalid custom endpoint', + provider: 'gcp', + masterKey: { + projectId: 'devprod-drivers', + location: 'global', + keyRing: 'key-ring-csfle', + keyName: 'key-name-csfle', + endpoint: 'example.com:443' + }, + succeed: false, + errorValidator: err => { + // Expect this to fail with an exception with a message containing the string: "parse error" + expect(err) + .to.be.an.instanceOf(Error) + .and.to.have.property('message') + .that.matches(/Invalid KMS response/); + } + } + ]; + + testCases.forEach(testCase => { + it(testCase.description, metadata, function () { + // 2. Call `client_encryption.createDataKey()` with "aws" as the provider and the following masterKey: + // .. code:: javascript + // { + // ... + // } + // Expect this to succeed. Use the returned UUID of the key to explicitly encrypt and decrypt the string "test" to validate it works. + const masterKey = testCase.masterKey; + + const promises = []; + promises.push( + this.clientEncryption.createDataKey(testCase.provider, { masterKey }).then( + keyId => { + if (!testCase.succeed) { + throw new Error( + 'Expected test case to fail to create data key, but it succeeded' + ); } - const expectedEvents = Array.from(testCase.expectedEvents); - const actualEvents = pruneEvents(this.commandStartedEvents.events); - - expect(actualEvents) - .to.have.a.lengthOf(expectedEvents.length) - .and.to.containSubset(expectedEvents); + return this.clientEncryption + .encrypt('test', { + keyId, + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' + }) + .then(encrypted => this.clientEncryption.decrypt(encrypted)) + .then(result => { + expect(result).to.equal('test'); + }); }, err => { - if (!testCase.error) { + if (testCase.succeed) { throw err; } + if (!testCase.errorValidator) { + throw new Error('Invalid Error validator'); + } + + testCase.errorValidator(err); } + ) + ); + + if (testCase.checkAgainstInvalid) { + promises.push( + this.clientEncryptionInvalid.createDataKey(testCase.provider, { masterKey }).then( + () => { + throw new Error( + 'Expected test case to fail to create data key, but it succeeded' + ); + }, + err => { + expect(err) + .property('message') + .to.match(/parse error/); + } + ) ); - }); + } + + return Promise.all(promises); }); + }); + }); - function pruneEvents(events) { - return events.map(event => { - // We are pruning out the bunch of repeating As, mostly - // b/c an error failure will try to print 2mb of 'a's - // and not have a good time. - event.command = Object.assign({}, event.command); - event.command.documents = event.command.documents.map(doc => { - doc = Object.assign({}, doc); - if (doc.unencrypted) { - doc.unencrypted = "Lots of repeating 'a's"; - } - return doc; + describe('BSON size limits and batch splitting', function () { + const fs = require('fs'); + const path = require('path'); + const { EJSON } = BSON; + function loadLimits(file) { + return EJSON.parse( + fs.readFileSync(path.resolve(__dirname, '../../spec/client-side-encryption/limits', file)) + ); + } + + const limitsSchema = loadLimits('limits-schema.json'); + const limitsKey = loadLimits('limits-key.json'); + const limitsDoc = loadLimits('limits-doc.json'); + + let hasRunFirstTimeSetup = false; + beforeEach(async function () { + if (hasRunFirstTimeSetup) { + // Even though we have to use a beforeEach here + // We still only want the following code to be run *once* + // before all the tests that follow + return; + } + hasRunFirstTimeSetup = true; + // First, perform the setup. + + // #. Create a MongoClient without encryption enabled (referred to as ``client``). + this.client = this.configuration.newClient(); + + await this.client + .connect() + // #. Using ``client``, drop and create the collection ``db.coll`` configured with the included JSON schema `limits/limits-schema.json <../limits/limits-schema.json>`_. + .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) + .then(() => { + return this.client.db(dataDbName).createCollection(dataCollName, { + validator: { $jsonSchema: limitsSchema } }); - return event; + }) + // #. Using ``client``, drop the collection ``keyvault.datakeys``. Insert the document `limits/limits-key.json <../limits/limits-key.json>`_ + .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) + .then(() => { + return this.client + .db(keyVaultDbName) + .collection(keyVaultCollName) + .insertOne(limitsKey, { writeConcern: { w: 'majority' } }); }); - } }); - describe('Views are prohibited', function () { - before(function () { - // First, perform the setup. + beforeEach(function () { + // #. Create a MongoClient configured with auto encryption (referred to as ``client_encrypted``) + // Configure with the ``local`` KMS provider as follows: + // .. code:: javascript + // { "local": { "key": } } + // Configure with the ``keyVaultNamespace`` set to ``keyvault.datakeys``. + this.clientEncrypted = this.configuration.newClient( + {}, + { + monitorCommands: true, + autoEncryption: { + keyVaultNamespace, + kmsProviders: getKmsProviders(LOCAL_KEY) + } + } + ); + return this.clientEncrypted.connect().then(() => { + this.encryptedColl = this.clientEncrypted.db(dataDbName).collection(dataCollName); + this.commandStartedEvents = new APMEventCollector( + this.clientEncrypted, + 'commandStarted', + { + include: ['insert'] + } + ); + }); + }); + + afterEach(function () { + if (this.commandStartedEvents) { + this.commandStartedEvents.teardown(); + this.commandStartedEvents = undefined; + } + if (this.clientEncrypted) { + return this.clientEncrypted.close(); + } + }); - // #. Create a MongoClient without encryption enabled (referred to as ``client``). - this.client = this.configuration.newClient(); + after(function () { + return this.client && this.client.close(); + }); - return this.client - .connect() - .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) - .then(() => { - return this.client.db(dataDbName).createCollection(dataCollName); + // Using ``client_encrypted`` perform the following operations: + + function repeatedChar(char, length) { + return Array.from({ length }) + .map(() => char) + .join(''); + } + + const testCases = [ + // #. Insert ``{ "_id": "over_2mib_under_16mib", "unencrypted": }``. + // Expect this to succeed since this is still under the ``maxBsonObjectSize`` limit. + { + description: 'should succeed for over_2mib_under_16mib', + docs: () => [{ _id: 'over_2mib_under_16mib', unencrypted: repeatedChar('a', 2097152) }], + expectedEvents: [{ commandName: 'insert' }] + }, + // #. 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 > }`` + // Note: limits-doc.json is a 1005 byte BSON document that encrypts to a ~10,000 byte document. + // Expect this to succeed since after encryption this still is below the normal maximum BSON document size. + // 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. + { + description: 'should succeed for encryption_exceeds_2mib', + docs: () => [ + Object.assign({}, limitsDoc, { + _id: 'encryption_exceeds_2mib', + unencrypted: repeatedChar('a', 2097152 - 2000) }) - .then(() => { - return this.client - .db(dataDbName) - .createCollection('view', { viewOn: dataCollName, pipeline: [] }) - .then(noop, noop); - }, noop); - }); - - after(function () { - return this.client && this.client.close(); - }); + ], + expectedEvents: [{ commandName: 'insert' }] + }, + // #. Bulk insert the following: + // - ``{ "_id": "over_2mib_1", "unencrypted": }`` + // - ``{ "_id": "over_2mib_2", "unencrypted": }`` + // Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). This may be verified using `command monitoring `_. + { + description: 'should succeed for bulk over_2mib', + docs: () => [ + { _id: 'over_2mib_1', unencrypted: repeatedChar('a', 2097152) }, + { _id: 'over_2mib_2', unencrypted: repeatedChar('a', 2097152) } + ], + expectedEvents: [{ commandName: 'insert' }, { commandName: 'insert' }] + }, + // #. Bulk insert the following: + // - 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 > }`` + // - 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 > }`` + // Expect the bulk write to succeed and split after first doc (i.e. two inserts occur). This may be verified using `command monitoring `_. + { + description: 'should succeed for bulk encryption_exceeds_2mib', + docs: () => [ + Object.assign({}, limitsDoc, { + _id: 'encryption_exceeds_2mib_1', + unencrypted: repeatedChar('a', 2097152 - 2000) + }), + Object.assign({}, limitsDoc, { + _id: 'encryption_exceeds_2mib_2', + unencrypted: repeatedChar('a', 2097152 - 2000) + }) + ], + expectedEvents: [{ commandName: 'insert' }, { commandName: 'insert' }] + }, + // #. Insert ``{ "_id": "under_16mib", "unencrypted": ``. + // Expect this to succeed since this is still (just) under the ``maxBsonObjectSize`` limit. + { + description: 'should succeed for under_16mib', + docs: () => [{ _id: 'under_16mib', unencrypted: repeatedChar('a', 16777216 - 2000) }], + expectedEvents: [{ commandName: 'insert' }] + }, + // #. Insert the document `limits/limits-doc.json <../limits/limits-doc.json>`_ concatenated with ``{ "_id": "encryption_exceeds_16mib", "unencrypted": < the string "a" repeated (16777216 - 2000) times > }`` + // Expect this to fail since encryption results in a document exceeding the ``maxBsonObjectSize`` limit. + { + description: 'should fail for encryption_exceeds_16mib', + docs: () => [ + Object.assign({}, limitsDoc, { + _id: 'encryption_exceeds_16mib', + unencrypted: repeatedChar('a', 16777216 - 2000) + }) + ], + error: true + } + ]; + + testCases.forEach(testCase => { + it(testCase.description, metadata, function () { + return this.encryptedColl.insertMany(testCase.docs()).then( + () => { + if (testCase.error) { + throw new Error('Expected this insert to fail, but it succeeded'); + } + const expectedEvents = Array.from(testCase.expectedEvents); + const actualEvents = pruneEvents(this.commandStartedEvents.events); - beforeEach(function () { - this.clientEncrypted = this.configuration.newClient( - {}, - { - autoEncryption: { - keyVaultNamespace, - kmsProviders: getKmsProviders(LOCAL_KEY) + expect(actualEvents) + .to.have.a.lengthOf(expectedEvents.length) + .and.to.containSubset(expectedEvents); + }, + err => { + if (!testCase.error) { + throw err; } } ); - - return this.clientEncrypted.connect(); }); + }); - afterEach(function () { - return this.clientEncrypted && this.clientEncrypted.close(); + function pruneEvents(events) { + return events.map(event => { + // We are pruning out the bunch of repeating As, mostly + // b/c an error failure will try to print 2mb of 'a's + // and not have a good time. + event.command = Object.assign({}, event.command); + event.command.documents = event.command.documents.map(doc => { + doc = Object.assign({}, doc); + if (doc.unencrypted) { + doc.unencrypted = "Lots of repeating 'a's"; + } + return doc; + }); + return event; }); + } + }); - it('should error when inserting into a view with autoEncryption', metadata, function () { - return this.clientEncrypted - .db(dataDbName) - .collection('view') - .insertOne({ a: 1 }) - .then( - () => { - throw new Error('Expected insert to fail, but it succeeded'); - }, - err => { - expect(err) - .to.have.property('message') - .that.matches(/cannot auto encrypt a view/); - } - ); - }); + describe('Views are prohibited', function () { + before(function () { + // First, perform the setup. + + // #. Create a MongoClient without encryption enabled (referred to as ``client``). + this.client = this.configuration.newClient(); + + return this.client + .connect() + .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) + .then(() => { + return this.client.db(dataDbName).createCollection(dataCollName); + }) + .then(() => { + return this.client + .db(dataDbName) + .createCollection('view', { viewOn: dataCollName, pipeline: [] }) + .then(noop, noop); + }, noop); }); - // TODO: We cannot implement these tests according to spec b/c the tests require a - // connect-less client. So instead we are implementing the tests via APM, - // and confirming that the externalClient is firing off keyVault requests during - // encrypted operations - describe('External Key Vault', function () { - const fs = require('fs'); - const path = require('path'); - const { EJSON } = BSON; - function loadExternal(file) { - return EJSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../../spec/client-side-encryption/external', file) - ) - ); - } + after(function () { + return this.client && this.client.close(); + }); - const externalKey = loadExternal('external-key.json'); - const externalSchema = loadExternal('external-schema.json'); + beforeEach(function () { + this.clientEncrypted = this.configuration.newClient( + {}, + { + autoEncryption: { + keyVaultNamespace, + kmsProviders: getKmsProviders(LOCAL_KEY) + } + } + ); - beforeEach(function () { - this.client = this.configuration.newClient(); + return this.clientEncrypted.connect(); + }); - // #. Create a MongoClient without encryption enabled (referred to as ``client``). - return ( - this.client - .connect() - // #. Using ``client``, drop the collections ``keyvault.datakeys`` and ``db.coll``. - // Insert the document `external/external-key.json <../external/external-key.json>`_ into ``keyvault.datakeys``. - .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) - .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) - .then(() => { - return this.client - .db(keyVaultDbName) - .collection(keyVaultCollName) - .insertOne(externalKey, { writeConcern: { w: 'majority' } }); - }) + afterEach(function () { + return this.clientEncrypted && this.clientEncrypted.close(); + }); + + it('should error when inserting into a view with autoEncryption', metadata, function () { + return this.clientEncrypted + .db(dataDbName) + .collection('view') + .insertOne({ a: 1 }) + .then( + () => { + throw new Error('Expected insert to fail, but it succeeded'); + }, + err => { + expect(err) + .to.have.property('message') + .that.matches(/cannot auto encrypt a view/); + } ); - }); + }); + }); - afterEach(function () { - if (this.commandStartedEvents) { - this.commandStartedEvents.teardown(); - this.commandStartedEvents = undefined; - } - return Promise.resolve() - .then(() => this.externalClient && this.externalClient.close()) - .then(() => this.clientEncrypted && this.clientEncrypted.close()) - .then(() => this.client && this.client.close()); - }); + // TODO: We cannot implement these tests according to spec b/c the tests require a + // connect-less client. So instead we are implementing the tests via APM, + // and confirming that the externalClient is firing off keyVault requests during + // encrypted operations + describe('External Key Vault', function () { + const fs = require('fs'); + const path = require('path'); + const { EJSON } = BSON; + function loadExternal(file) { + return EJSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../../spec/client-side-encryption/external', file) + ) + ); + } + + const externalKey = loadExternal('external-key.json'); + const externalSchema = loadExternal('external-schema.json'); + + beforeEach(function () { + this.client = this.configuration.newClient(); + + // #. Create a MongoClient without encryption enabled (referred to as ``client``). + return ( + this.client + .connect() + // #. Using ``client``, drop the collections ``keyvault.datakeys`` and ``db.coll``. + // Insert the document `external/external-key.json <../external/external-key.json>`_ into ``keyvault.datakeys``. + .then(() => dropCollection(this.client.db(dataDbName), dataCollName)) + .then(() => dropCollection(this.client.db(keyVaultDbName), keyVaultCollName)) + .then(() => { + return this.client + .db(keyVaultDbName) + .collection(keyVaultCollName) + .insertOne(externalKey, { writeConcern: { w: 'majority' } }); + }) + ); + }); - function defineTest(withExternalKeyVault) { - it( - `should work ${withExternalKeyVault ? 'with' : 'without'} external key vault`, - metadata, - function () { - const ClientEncryption = this.configuration.mongodbClientEncryption.ClientEncryption; - return ( - Promise.resolve() - .then(() => { - // If ``withExternalKeyVault == true``, configure both objects with an external key vault client. The external client MUST connect to the same - // MongoDB cluster that is being tested against, except it MUST use the username ``fake-user`` and password ``fake-pwd``. - this.externalClient = this.configuration.newClient( - // this.configuration.url('fake-user', 'fake-pwd'), - // TODO: Do this properly - {}, - { monitorCommands: true } - ); - - this.commandStartedEvents = new APMEventCollector( - this.externalClient, - 'commandStarted', - { - include: ['find'] - } - ); - return this.externalClient.connect(); - }) - // #. Create the following: - // - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) - // - A ``ClientEncryption`` object (referred to as ``client_encryption``) - // Configure both objects with the ``local`` KMS providers as follows: - // .. code:: javascript - // { "local": { "key": } } - // Configure both objects with ``keyVaultNamespace`` set to ``keyvault.datakeys``. - // 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": }`` - .then(() => { - const options = { - bson: BSON, - keyVaultNamespace, - kmsProviders: getKmsProviders(LOCAL_KEY) - }; - - if (withExternalKeyVault) { - options.keyVaultClient = this.externalClient; + afterEach(function () { + if (this.commandStartedEvents) { + this.commandStartedEvents.teardown(); + this.commandStartedEvents = undefined; + } + return Promise.resolve() + .then(() => this.externalClient && this.externalClient.close()) + .then(() => this.clientEncrypted && this.clientEncrypted.close()) + .then(() => this.client && this.client.close()); + }); + + function defineTest(withExternalKeyVault) { + it( + `should work ${withExternalKeyVault ? 'with' : 'without'} external key vault`, + metadata, + function () { + const ClientEncryption = this.configuration.mongodbClientEncryption.ClientEncryption; + return ( + Promise.resolve() + .then(() => { + // If ``withExternalKeyVault == true``, configure both objects with an external key vault client. The external client MUST connect to the same + // MongoDB cluster that is being tested against, except it MUST use the username ``fake-user`` and password ``fake-pwd``. + this.externalClient = this.configuration.newClient( + // this.configuration.url('fake-user', 'fake-pwd'), + // TODO: Do this properly + {}, + { monitorCommands: true } + ); + + this.commandStartedEvents = new APMEventCollector( + this.externalClient, + 'commandStarted', + { + include: ['find'] } + ); + return this.externalClient.connect(); + }) + // #. Create the following: + // - A MongoClient configured with auto encryption (referred to as ``client_encrypted``) + // - A ``ClientEncryption`` object (referred to as ``client_encryption``) + // Configure both objects with the ``local`` KMS providers as follows: + // .. code:: javascript + // { "local": { "key": } } + // Configure both objects with ``keyVaultNamespace`` set to ``keyvault.datakeys``. + // 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": }`` + .then(() => { + const options = { + bson: BSON, + keyVaultNamespace, + kmsProviders: getKmsProviders(LOCAL_KEY) + }; + + if (withExternalKeyVault) { + options.keyVaultClient = this.externalClient; + } - this.clientEncryption = new ClientEncryption( - this.client, - Object.assign({}, options) - ); - this.clientEncrypted = this.configuration.newClient( - {}, - { - autoEncryption: Object.assign({}, options, { - schemaMap: { - 'db.coll': externalSchema - } - }) - } - ); - return this.clientEncrypted.connect(); - }) - .then(() => { - // #. Use ``client_encrypted`` to insert the document ``{"encrypted": "test"}`` into ``db.coll``. - // If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed. - this.commandStartedEvents.clear(); - return this.clientEncrypted - .db(dataDbName) - .collection(dataCollName) - .insertOne({ encrypted: 'test' }) - .then(() => { - if (withExternalKeyVault) { - expect(this.commandStartedEvents.events).to.containSubset([ - { - commandName: 'find', - databaseName: keyVaultDbName, - command: { find: keyVaultCollName } - } - ]); - } else { - expect(this.commandStartedEvents.events).to.not.containSubset([ - { - commandName: 'find', - databaseName: keyVaultDbName, - command: { find: keyVaultCollName } - } - ]); + this.clientEncryption = new ClientEncryption( + this.client, + Object.assign({}, options) + ); + this.clientEncrypted = this.configuration.newClient( + {}, + { + autoEncryption: Object.assign({}, options, { + schemaMap: { + 'db.coll': externalSchema } - }); - // TODO: Do this in the spec-compliant way using bad auth credentials - // .then( - // () => { - // if (withExternalKeyVault) { - // throw new Error( - // 'expected insert to fail with authentication error, but it passed' - // ); - // } - // }, - // err => { - // if (!withExternalKeyVault) { - // throw err; - // } - // expect(err).to.be.an.instanceOf(Error); - // } - // ); - }) - .then(() => { - // #. Use ``client_encryption`` to explicitly encrypt the string ``"test"`` with key ID ``LOCALAAAAAAAAAAAAAAAAA==`` and deterministic algorithm. - // If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed. - this.commandStartedEvents.clear(); - return this.clientEncryption - .encrypt('test', { - keyId: externalKey._id, - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' }) - .then(() => { - if (withExternalKeyVault) { - expect(this.commandStartedEvents.events).to.containSubset([ - { - commandName: 'find', - databaseName: keyVaultDbName, - command: { find: keyVaultCollName } - } - ]); - } else { - expect(this.commandStartedEvents.events).to.not.containSubset([ - { - commandName: 'find', - databaseName: keyVaultDbName, - command: { find: keyVaultCollName } - } - ]); - } - }); - // TODO: Do this in the spec-compliant way using bad auth credentials - // .then( - // () => { - // if (withExternalKeyVault) { - // throw new Error( - // 'expected insert to fail with authentication error, but it passed' - // ); - // } - // }, - // err => { - // if (!withExternalKeyVault) { - // throw err; - // } - // expect(err).to.be.an.instanceOf(Error); - // } - // ); - }) - ); - } - ); - } - // Run the following tests twice, parameterized by a boolean ``withExternalKeyVault``. - defineTest(true); - defineTest(false); - }); - - deadlockTests(metadata); + } + ); + return this.clientEncrypted.connect(); + }) + .then(() => { + // #. Use ``client_encrypted`` to insert the document ``{"encrypted": "test"}`` into ``db.coll``. + // If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed. + this.commandStartedEvents.clear(); + return this.clientEncrypted + .db(dataDbName) + .collection(dataCollName) + .insertOne({ encrypted: 'test' }) + .then(() => { + if (withExternalKeyVault) { + expect(this.commandStartedEvents.events).to.containSubset([ + { + commandName: 'find', + databaseName: keyVaultDbName, + command: { find: keyVaultCollName } + } + ]); + } else { + expect(this.commandStartedEvents.events).to.not.containSubset([ + { + commandName: 'find', + databaseName: keyVaultDbName, + command: { find: keyVaultCollName } + } + ]); + } + }); + // TODO: Do this in the spec-compliant way using bad auth credentials + // .then( + // () => { + // if (withExternalKeyVault) { + // throw new Error( + // 'expected insert to fail with authentication error, but it passed' + // ); + // } + // }, + // err => { + // if (!withExternalKeyVault) { + // throw err; + // } + // expect(err).to.be.an.instanceOf(Error); + // } + // ); + }) + .then(() => { + // #. Use ``client_encryption`` to explicitly encrypt the string ``"test"`` with key ID ``LOCALAAAAAAAAAAAAAAAAA==`` and deterministic algorithm. + // If ``withExternalKeyVault == true``, expect an authentication exception to be thrown. Otherwise, expect the insert to succeed. + this.commandStartedEvents.clear(); + return this.clientEncryption + .encrypt('test', { + keyId: externalKey._id, + algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' + }) + .then(() => { + if (withExternalKeyVault) { + expect(this.commandStartedEvents.events).to.containSubset([ + { + commandName: 'find', + databaseName: keyVaultDbName, + command: { find: keyVaultCollName } + } + ]); + } else { + expect(this.commandStartedEvents.events).to.not.containSubset([ + { + commandName: 'find', + databaseName: keyVaultDbName, + command: { find: keyVaultCollName } + } + ]); + } + }); + // TODO: Do this in the spec-compliant way using bad auth credentials + // .then( + // () => { + // if (withExternalKeyVault) { + // throw new Error( + // 'expected insert to fail with authentication error, but it passed' + // ); + // } + // }, + // err => { + // if (!withExternalKeyVault) { + // throw err; + // } + // expect(err).to.be.an.instanceOf(Error); + // } + // ); + }) + ); + } + ); + } + // Run the following tests twice, parameterized by a boolean ``withExternalKeyVault``. + defineTest(true); + defineTest(false); }); -} + + deadlockTests(metadata); +}); From c4756e6d30ae7caed59f8980139227355133c691 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 13:13:02 +0100 Subject: [PATCH 51/73] test(NODE-3777): fix lint errors --- .../client_side_encryption.prose.test.js | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 3bee277da02..d5166450bee 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -926,9 +926,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { this.clientEncryption.createDataKey(testCase.provider, { masterKey }).then( keyId => { if (!testCase.succeed) { - throw new Error( - 'Expected test case to fail to create data key, but it succeeded' - ); + throw new Error('Expected test case to fail to create data key, but it succeeded'); } return this.clientEncryption .encrypt('test', { @@ -957,9 +955,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { promises.push( this.clientEncryptionInvalid.createDataKey(testCase.provider, { masterKey }).then( () => { - throw new Error( - 'Expected test case to fail to create data key, but it succeeded' - ); + throw new Error('Expected test case to fail to create data key, but it succeeded'); }, err => { expect(err) @@ -1040,13 +1036,9 @@ describe('Client Side Encryption Prose Tests', metadata, function () { ); return this.clientEncrypted.connect().then(() => { this.encryptedColl = this.clientEncrypted.db(dataDbName).collection(dataCollName); - this.commandStartedEvents = new APMEventCollector( - this.clientEncrypted, - 'commandStarted', - { - include: ['insert'] - } - ); + this.commandStartedEvents = new APMEventCollector(this.clientEncrypted, 'commandStarted', { + include: ['insert'] + }); }); }); @@ -1257,9 +1249,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { const { EJSON } = BSON; function loadExternal(file) { return EJSON.parse( - fs.readFileSync( - path.resolve(__dirname, '../../spec/client-side-encryption/external', file) - ) + fs.readFileSync(path.resolve(__dirname, '../../spec/client-side-encryption/external', file)) ); } From 27ae5e9c996925427472589cee1a41541c882e14 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 13:20:54 +0100 Subject: [PATCH 52/73] test(NODE-3777): add failure expectations in prose test --- .../client_side_encryption.prose.test.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index d5166450bee..a623372e28d 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -141,6 +141,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with invalid provider host', metadata, async function () { try { await clientEncryptionInvalid.createDataKey('kmip', { masterKey }); + expect.fail('it must fail with invlalid host'); } catch (e) { expect(e.message).to.equal('KMS request failed'); } @@ -190,6 +191,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with invalid provider host', metadata, async function () { try { await clientEncryption.createDataKey('kmip', { masterKey }); + expect.fail('it must fail with invlalid host'); } catch (e) { expect(e.message).to.equal('KMS request failed'); } @@ -334,6 +336,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with no tls', metadata, async function () { try { await clientEncryptionNoTls.createDataKey('aws', { masterKey }); + expect.fail('it must fail with no tls'); } catch (e) { expect(e.originalError.message).to.include('certificate required'); } @@ -342,6 +345,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('passes with tls but fails to parse', metadata, async function () { try { await clientEncryptionWithTls.createDataKey('aws', { masterKey }); + expect.fail('it must fail to parse response'); } catch (e) { expect(e.message).to.include('parse error'); } @@ -350,6 +354,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with expired certificates', metadata, async function () { try { await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); + expect.fail('it must fail with invalid certificate'); } catch (e) { expect(e.message).to.include('expected UTF-8 key'); } @@ -360,6 +365,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { await clientEncryptionWithInvalidHostname.createDataKey('aws', { masterKeyInvalidHostname }); + expect.fail('it must fail with invalid hostnames'); } catch (e) { expect(e.message).to.include('expected UTF-8 key'); } @@ -376,6 +382,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with no tls', metadata, async function () { try { await clientEncryptionNoTls.createDataKey('azure', { masterKey }); + expect.fail('it must fail with no tls'); } catch (e) { expect(e.originalError.message).to.include('certificate required'); } @@ -384,6 +391,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with invalid host', metadata, async function () { try { await clientEncryptionWithTls.createDataKey('azure', { masterKey }); + expect.fail('it must fail with invalid host'); } catch (e) { expect(e.message).to.include('HTTP status=404'); } @@ -392,6 +400,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with expired certificates', metadata, async function () { try { await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); + expect.fail('it must fail with expired certificates'); } catch (e) { expect(e.originalError.message).to.include('certificate has expired'); } @@ -400,6 +409,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with invalid hostnames', metadata, async function () { try { await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); + expect.fail('it must fail with invalid hostnames'); } catch (e) { expect(e.originalError.message).to.include('does not match certificate'); } @@ -418,6 +428,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with no tls', metadata, async function () { try { await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); + expect.fail('it must fail with no tls'); } catch (e) { expect(e.originalError.message).to.include('certificate required'); } @@ -426,6 +437,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with invalid host', metadata, async function () { try { await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); + expect.fail('it must fail with invalid host'); } catch (e) { expect(e.message).to.include('HTTP status=404'); } @@ -434,6 +446,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with expired certificates', metadata, async function () { try { await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); + expect.fail('it must fail with expired certificates'); } catch (e) { expect(e.originalError.message).to.include('certificate has expired'); } @@ -442,6 +455,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with invalid hostnames', metadata, async function () { try { await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); + expect.fail('it must fail with invalid hostnames'); } catch (e) { expect(e.originalError.message).to.include('does not match certificate'); } @@ -453,6 +467,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with no tls', metadata, async function () { try { await clientEncryptionNoTls.createDataKey('kmip'); + expect.fail('it must fail with no tls'); } catch (e) { expect(e.originalError.message).to.include('before secure TLS connection'); } @@ -461,6 +476,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with expired certificates', metadata, async function () { try { await clientEncryptionWithTlsExpired.createDataKey('kmip'); + expect.fail('it must fail with expired certificates'); } catch (e) { expect(e.originalError.message).to.include('certificate has expired'); } @@ -469,6 +485,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { it('fails with invalid hostnames', metadata, async function () { try { await clientEncryptionWithInvalidHostname.createDataKey('kmip'); + expect.fail('it must fail with invalid hostnames'); } catch (e) { expect(e.originalError.message).to.include('does not match certificate'); } From e5e35ec2b276665200d64620accc8a09549e47cb Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 15:13:07 +0100 Subject: [PATCH 53/73] test(NODE-3777): bring back shell exec --- .evergreen/config.yml | 2 +- .evergreen/config.yml.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 14e5e361ca1..5409dca48f5 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -108,7 +108,7 @@ functions: cd ${DRIVERS_TOOLS}/.evergreen/csfle . ./activate_venv.sh fi - - command: subprocess.exec + - command: shell.exec params: background: true script: | diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index 8ceaf2ed58f..cd3add2a6f4 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -128,7 +128,7 @@ functions: cd ${DRIVERS_TOOLS}/.evergreen/csfle . ./activate_venv.sh fi - - command: subprocess.exec + - command: shell.exec params: background: true script: | From 2f1da7dd8b4e56bff4e688b2314355ac79b4f2a6 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 15:20:30 +0100 Subject: [PATCH 54/73] test(NODE-3777): use subprocess for kms servers --- .evergreen/config.yml | 24 ++++++------------------ .evergreen/config.yml.in | 24 ++++++------------------ .evergreen/run-kms-servers.sh | 9 +++++++++ 3 files changed, 21 insertions(+), 36 deletions(-) create mode 100644 .evergreen/run-kms-servers.sh diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 5409dca48f5..a0824be35b3 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -100,26 +100,14 @@ functions: ${PREPARE_SHELL} DRIVERS_TOOLS="${DRIVERS_TOOLS}" bash ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/run-mongohouse-local.sh bootstrap kms servers: - - command: shell.exec - params: - script: | - ${PREPARE_SHELL} - if [ -n "${CLIENT_ENCRYPTION}" ]; then - cd ${DRIVERS_TOOLS}/.evergreen/csfle - . ./activate_venv.sh - fi - - command: shell.exec + - command: subprocess.exec params: background: true - script: | - if [ -n "${CLIENT_ENCRYPTION}" ]; then - cd ${DRIVERS_TOOLS}/.evergreen/csfle - # by default it always runs on port 5698 - ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & - fi + working_dir: src + binary: bash .evergreen/run-kms-servers.sh + env: + CLIENT_ENCRYPTION: ${CLIENT_ENCRYPTION} + DRIVERS_TOOLS: ${DRIVERS_TOOLS} run tests: - command: shell.exec type: test diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index cd3add2a6f4..c8c046b2a94 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -120,26 +120,14 @@ functions: DRIVERS_TOOLS="${DRIVERS_TOOLS}" bash ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/run-mongohouse-local.sh "bootstrap kms servers": - - command: shell.exec - params: - script: | - ${PREPARE_SHELL} - if [ -n "${CLIENT_ENCRYPTION}" ]; then - cd ${DRIVERS_TOOLS}/.evergreen/csfle - . ./activate_venv.sh - fi - - command: shell.exec + - command: subprocess.exec params: background: true - script: | - if [ -n "${CLIENT_ENCRYPTION}" ]; then - cd ${DRIVERS_TOOLS}/.evergreen/csfle - # by default it always runs on port 5698 - ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & - fi + working_dir: src + binary: bash .evergreen/run-kms-servers.sh + env: + CLIENT_ENCRYPTION: ${CLIENT_ENCRYPTION} + DRIVERS_TOOLS: ${DRIVERS_TOOLS} "run tests": - command: shell.exec type: test diff --git a/.evergreen/run-kms-servers.sh b/.evergreen/run-kms-servers.sh new file mode 100644 index 00000000000..dbbbffa4a05 --- /dev/null +++ b/.evergreen/run-kms-servers.sh @@ -0,0 +1,9 @@ +if [ -n "${CLIENT_ENCRYPTION}" ]; then + cd ${DRIVERS_TOOLS}/.evergreen/csfle + . ./activate_venv.sh + # by default it always runs on port 5698 + ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & + ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & +fi From b7846effb81d0547ac72514e7ee184e52e271a45 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 15:37:06 +0100 Subject: [PATCH 55/73] refactor(NODE-3777): cleanup kmsProviders method --- .../client-side-encryption/driver.test.js | 2 +- test/tools/runner/config.ts | 21 ++----------------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/test/integration/client-side-encryption/driver.test.js b/test/integration/client-side-encryption/driver.test.js index ed7496e60f1..f9924c6440c 100644 --- a/test/integration/client-side-encryption/driver.test.js +++ b/test/integration/client-side-encryption/driver.test.js @@ -73,7 +73,7 @@ describe('Client Side Encryption Functional', function () { let keyVaultDb; const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - const kmsProviders = this.configuration.kmsProviders('local', crypto.randomBytes(96)); + const kmsProviders = this.configuration.kmsProviders(crypto.randomBytes(96)); return this.client .connect() .then(() => { diff --git a/test/tools/runner/config.ts b/test/tools/runner/config.ts index cd058b3858e..904336380b5 100644 --- a/test/tools/runner/config.ts +++ b/test/tools/runner/config.ts @@ -357,24 +357,7 @@ export class TestConfiguration { return this.clientSideEncryption && this.clientSideEncryption.mongodbClientEncryption; } - kmsProviders(type, localKey) { - const kmsProviders: Record = {}; - if (typeof type !== 'string' || type === 'aws') { - kmsProviders.aws = { - accessKeyId: this.clientSideEncryption.AWS_ACCESS_KEY_ID, - secretAccessKey: this.clientSideEncryption.AWS_SECRET_ACCESS_KEY - }; - } - if (typeof type !== 'string' || type === 'local') { - kmsProviders.local = { - key: localKey - }; - } - if (typeof type !== 'string' || type === 'kmip') { - kmsProviders.kmip = { - endpoint: 'localhost:5698' - }; - } - return kmsProviders; + kmsProviders(localKey): Record { + return { local: { key: localKey }}; } } From 8abed87a15b41b1bbd0ffc06666786c0708efddb Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 15:49:35 +0100 Subject: [PATCH 56/73] fix(NODE-3777): lint error --- test/tools/runner/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tools/runner/config.ts b/test/tools/runner/config.ts index 904336380b5..993de18a0fd 100644 --- a/test/tools/runner/config.ts +++ b/test/tools/runner/config.ts @@ -358,6 +358,6 @@ export class TestConfiguration { } kmsProviders(localKey): Record { - return { local: { key: localKey }}; + return { local: { key: localKey } }; } } From 1aaf18187d6866f1d709490680a31c247c9721c7 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 16:03:11 +0100 Subject: [PATCH 57/73] test(NODE-3777): remove unused env var --- .evergreen/config.yml | 6 ++---- .evergreen/config.yml.in | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index a0824be35b3..51024d93709 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -83,7 +83,7 @@ functions: ORCHESTRATION_FILE=${ORCHESTRATION_FILE} \ REQUIRE_API_VERSION=${REQUIRE_API_VERSION} \ LOAD_BALANCER=${LOAD_BALANCER} \ - bash ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh + sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh - command: expansions.update params: file: mo-expansion.yml @@ -182,8 +182,7 @@ functions: - command: shell.exec params: script: | - DRIVERS_TOOLS=${DRIVERS_TOOLS} MONGODB_URI=${MONGODB_URI} \ - bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh start + MONGODB_URI=${MONGODB_URI} bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh start - command: expansions.update params: file: lb-expansion.yml @@ -191,7 +190,6 @@ functions: - command: shell.exec params: script: | - DRIVERS_TOOLS=${DRIVERS_TOOLS} MONGODB_URI=${MONGODB_URI} \ bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh stop run-lb-tests: - command: shell.exec diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index c8c046b2a94..9527f69ca5b 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -100,7 +100,7 @@ functions: ORCHESTRATION_FILE=${ORCHESTRATION_FILE} \ REQUIRE_API_VERSION=${REQUIRE_API_VERSION} \ LOAD_BALANCER=${LOAD_BALANCER} \ - bash ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh + sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh # run-orchestration generates expansion file with the MONGODB_URI for the cluster - command: expansions.update params: @@ -204,8 +204,7 @@ functions: - command: shell.exec params: script: | - DRIVERS_TOOLS=${DRIVERS_TOOLS} MONGODB_URI=${MONGODB_URI} \ - bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh start + MONGODB_URI=${MONGODB_URI} bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh start - command: expansions.update params: file: lb-expansion.yml @@ -214,7 +213,6 @@ functions: - command: shell.exec params: script: | - DRIVERS_TOOLS=${DRIVERS_TOOLS} MONGODB_URI=${MONGODB_URI} \ bash ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh stop "run-lb-tests": From d76c8f80aa3cb3dbecb17556cfc0554cbb99a4d6 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 16:26:20 +0100 Subject: [PATCH 58/73] fix(NODE-3777): no skips in after blocks --- .../client-side-encryption/client_side_encryption.prose.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index a623372e28d..42817fa881f 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -103,7 +103,6 @@ describe('Client Side Encryption Prose Tests', metadata, function () { }); after(async function () { - if (process.env.LOAD_BALANCER) this.skip(); await client.close(); }); @@ -316,7 +315,6 @@ describe('Client Side Encryption Prose Tests', metadata, function () { }); afterEach(async function () { - if (process.env.LOAD_BALANCER) this.skip(); await clientNoTls.close(); await clientWithTls.close(); await clientWithTlsExpired.close(); From 06d41480455df149b71b37a4dc00c3de2e98bdc0 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Mon, 7 Feb 2022 16:56:29 +0100 Subject: [PATCH 59/73] test(NODE-3777): skip after client creation --- .../client-side-encryption/client_side_encryption.prose.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 42817fa881f..21c8dc9dded 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -81,8 +81,8 @@ describe('Client Side Encryption Prose Tests', metadata, function () { let clientEncryptionInvalid; before(async function () { - if (process.env.LOAD_BALANCER) this.skip(); client = this.configuration.newClient(); + if (process.env.LOAD_BALANCER) this.skip(); await client.connect(); const mongodbClientEncryption = this.configuration.mongodbClientEncryption; clientEncryption = new mongodbClientEncryption.ClientEncryption(client, { From 696d6fd8d65231812d7e33ff17ff599394b1aa40 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 8 Feb 2022 12:43:51 +0100 Subject: [PATCH 60/73] fix(NODE-3777): bring back test comment --- test/manual/kerberos.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/manual/kerberos.test.js b/test/manual/kerberos.test.js index bfc3294a2fc..32764d19f07 100644 --- a/test/manual/kerberos.test.js +++ b/test/manual/kerberos.test.js @@ -51,6 +51,7 @@ describe('Kerberos', function () { }); }); + // Unskip this test when a proper setup is available - see NODE-3060 it.skip('validate that SERVICE_REALM and CANONICALIZE_HOST_NAME can be passed in', function (done) { const client = new MongoClient( `${krb5Uri}&authMechanismProperties=SERVICE_NAME:mongodb,CANONICALIZE_HOST_NAME:false,SERVICE_REALM:windows&maxPoolSize=1` From 5cdc33cbe7e91a108027e5d84211af299ebcd974 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 8 Feb 2022 13:04:55 +0100 Subject: [PATCH 61/73] test(NODE-3777): update prose test structure --- .../client_side_encryption.prose.test.js | 514 +++++++----------- 1 file changed, 204 insertions(+), 310 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 21c8dc9dded..2b68f8db164 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -61,152 +61,13 @@ describe('Client Side Encryption Prose Tests', metadata, function () { 'base64' ); - context('when kmip is the kms provider', metadata, async function () { - const autoEncryptionOptions = { - keyVaultNamespace, - kmsProviders: { - kmip: { - endpoint: 'localhost:5698' - } - }, - tlsOptions: { - kmip: { - tlsCAFile: process.env.KMIP_TLS_CA_FILE, - tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE - } - } - }; - let client; - let clientEncryption; - let clientEncryptionInvalid; - - before(async function () { - client = this.configuration.newClient(); - if (process.env.LOAD_BALANCER) this.skip(); - await client.connect(); - const mongodbClientEncryption = this.configuration.mongodbClientEncryption; - clientEncryption = new mongodbClientEncryption.ClientEncryption(client, { - ...autoEncryptionOptions, - bson: BSON - }); - clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(client, { - ...autoEncryptionOptions, - bson: BSON, - kmsProviders: { - kmip: { - endpoint: 'invalid.localhost:5698' - } - } - }); - await dropCollection(client.db(keyVaultDbName), keyVaultCollName); - await dropCollection(client.db(keyVaultDbName), keyVaultCollName); - }); - - after(async function () { - await client.close(); - }); - - context('when encrypting with kmip', metadata, async function () { - context('when not providing an endpoint in the master key', metadata, async function () { - const masterKey = { keyId: '1' }; - let dataKey; - let encrypted; - let decrypted; - - /** - * 10. - * - Create data key with kmip as provider and master key of { keyId: '1' } - * - Use UUID to encrypt and decrypt to value. - * - Create data key with invalid encrypter and expect failure. - */ - before(async function () { - if (process.env.LOAD_BALANCER) this.skip(); - dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); - encrypted = await clientEncryption.encrypt('test', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: dataKey - }); - decrypted = await clientEncryption.decrypt(encrypted); - }); - - it('must create a data key', metadata, function () { - expect(dataKey).to.have.property('sub_type', 4); - }); - - it('properly encrypts and decrypts', metadata, function () { - expect(decrypted).to.equal('test'); - }); - - it('fails with invalid provider host', metadata, async function () { - try { - await clientEncryptionInvalid.createDataKey('kmip', { masterKey }); - expect.fail('it must fail with invlalid host'); - } catch (e) { - expect(e.message).to.equal('KMS request failed'); - } - }); - }); - - context('when providing an endpoint in the master key', metadata, function () { - context('when the endpoint is valid', metadata, function () { - const masterKey = { keyId: '1', endpoint: 'localhost:5698' }; - let dataKey; - let encrypted; - let decrypted; - - /** - * 11. - * - Create data key with kmip as provider and master key of - * { keyId: 1, endpoint: 'localhost:5698 '} - * - Use UUID to encrypt and decrypt to value. - */ - before(async function () { - dataKey = await clientEncryption.createDataKey('kmip', { masterKey }); - encrypted = await clientEncryption.encrypt('test', { - algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic', - keyId: dataKey - }); - decrypted = await clientEncryption.decrypt(encrypted); - }); - - it('must create a data key', metadata, function () { - expect(dataKey).to.have.property('sub_type', 4); - }); - - it('properly encrypts and decrypts', metadata, function () { - expect(decrypted).to.equal('test'); - }); - }); - - context('when the endpoint is invalid', metadata, function () { - const masterKey = { keyId: '1', endpoint: 'doesnotexist.localhost:5698' }; - - /** - * 12. - * - Create data key with kmip as provider and master key of - * { keyId: 1, endpoint: 'doesnotexist.localhost:5698 '} - * - Expect failure. - */ - it('fails with invalid provider host', metadata, async function () { - try { - await clientEncryption.createDataKey('kmip', { masterKey }); - expect.fail('it must fail with invlalid host'); - } catch (e) { - expect(e.message).to.equal('KMS request failed'); - } - }); - }); - }); - }); - }); - /** * - Create client encryption no tls * - Create client encryption with tls * - Create client encryption expired * - Create client encryption invalid hostname */ - context('when passing through tls options', metadata, async function () { + context('KMS TLS Options Tests', metadata, async function () { let tlsCaOptions; let clientNoTlsOptions; let clientWithTlsOptions; @@ -303,191 +164,191 @@ describe('Client Side Encryption Prose Tests', metadata, function () { ); }); - context('when using tls clients', metadata, function () { - beforeEach('connecting tls clients', async function () { - if (process.env.LOAD_BALANCER) this.skip(); - await clientNoTls.connect(); - await clientWithTls.connect(); - await clientWithTlsExpired.connect(); - await clientWithInvalidHostname.connect(); - await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); - await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); + beforeEach(async function () { + if (process.env.LOAD_BALANCER) this.skip(); + await clientNoTls.connect(); + await clientWithTls.connect(); + await clientWithTlsExpired.connect(); + await clientWithInvalidHostname.connect(); + await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); + await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); + }); + + afterEach(async function () { + await clientNoTls.close(); + await clientWithTls.close(); + await clientWithTlsExpired.close(); + await clientWithInvalidHostname.close(); + }); + + // Case 1. + context('Case 1: AWS', metadata, function () { + const masterKey = { + region: 'us-east-1', + key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + endpoint: '127.0.0.1:8002' + }; + const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; + const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; + + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('aws', { masterKey }); + expect.fail('it must fail with no tls'); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } }); - afterEach(async function () { - await clientNoTls.close(); - await clientWithTls.close(); - await clientWithTlsExpired.close(); - await clientWithInvalidHostname.close(); + it('passes with tls but fails to parse', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('aws', { masterKey }); + expect.fail('it must fail to parse response'); + } catch (e) { + expect(e.message).to.include('parse error'); + } }); - // Case 1. - context('when using aws', metadata, function () { - const masterKey = { - region: 'us-east-1', - key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: '127.0.0.1:8002' - }; - const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; - const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; - - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('aws', { masterKey }); - expect.fail('it must fail with no tls'); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); + expect.fail('it must fail with invalid certificate'); + } catch (e) { + expect(e.message).to.include('expected UTF-8 key'); + } + }); - it('passes with tls but fails to parse', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('aws', { masterKey }); - expect.fail('it must fail to parse response'); - } catch (e) { - expect(e.message).to.include('parse error'); - } - }); + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('aws', { + masterKeyInvalidHostname + }); + expect.fail('it must fail with invalid hostnames'); + } catch (e) { + expect(e.message).to.include('expected UTF-8 key'); + } + }); + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); - expect.fail('it must fail with invalid certificate'); - } catch (e) { - expect(e.message).to.include('expected UTF-8 key'); - } - }); + // Case 2. + context('Case 2: Azure', metadata, function () { + const masterKey = { + keyVaultEndpoint: 'doesnotexist.local', + keyName: 'foo' + }; - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('aws', { - masterKeyInvalidHostname - }); - expect.fail('it must fail with invalid hostnames'); - } catch (e) { - expect(e.message).to.include('expected UTF-8 key'); - } - }); + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('azure', { masterKey }); + expect.fail('it must fail with no tls'); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } }); - // Case 2. - context('when using azure', metadata, function () { - const masterKey = { - keyVaultEndpoint: 'doesnotexist.local', - keyName: 'foo' - }; - - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('azure', { masterKey }); - expect.fail('it must fail with no tls'); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } - }); - - it('fails with invalid host', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('azure', { masterKey }); - expect.fail('it must fail with invalid host'); - } catch (e) { - expect(e.message).to.include('HTTP status=404'); - } - }); + it('fails with invalid host', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('azure', { masterKey }); + expect.fail('it must fail with invalid host'); + } catch (e) { + expect(e.message).to.include('HTTP status=404'); + } + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); - expect.fail('it must fail with expired certificates'); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); + expect.fail('it must fail with expired certificates'); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); - expect.fail('it must fail with invalid hostnames'); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } - }); + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); + expect.fail('it must fail with invalid hostnames'); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } }); + }); - // Case 3. - context('when using gcp', metadata, function () { - const masterKey = { - projectId: 'foo', - location: 'bar', - keyRing: 'baz', - keyName: 'foo' - }; - - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); - expect.fail('it must fail with no tls'); - } catch (e) { - expect(e.originalError.message).to.include('certificate required'); - } - }); + // Case 3. + context('Case 3: GCP', metadata, function () { + const masterKey = { + projectId: 'foo', + location: 'bar', + keyRing: 'baz', + keyName: 'foo' + }; - it('fails with invalid host', metadata, async function () { - try { - await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); - expect.fail('it must fail with invalid host'); - } catch (e) { - expect(e.message).to.include('HTTP status=404'); - } - }); + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); + expect.fail('it must fail with no tls'); + } catch (e) { + expect(e.originalError.message).to.include('certificate required'); + } + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); - expect.fail('it must fail with expired certificates'); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } - }); + it('fails with invalid host', metadata, async function () { + try { + await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); + expect.fail('it must fail with invalid host'); + } catch (e) { + expect(e.message).to.include('HTTP status=404'); + } + }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); - expect.fail('it must fail with invalid hostnames'); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); + expect.fail('it must fail with expired certificates'); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } }); - // Case 4. - context('when using kmip', metadata, function () { - it('fails with no tls', metadata, async function () { - try { - await clientEncryptionNoTls.createDataKey('kmip'); - expect.fail('it must fail with no tls'); - } catch (e) { - expect(e.originalError.message).to.include('before secure TLS connection'); - } - }); + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); + expect.fail('it must fail with invalid hostnames'); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } + }); + }); - it('fails with expired certificates', metadata, async function () { - try { - await clientEncryptionWithTlsExpired.createDataKey('kmip'); - expect.fail('it must fail with expired certificates'); - } catch (e) { - expect(e.originalError.message).to.include('certificate has expired'); - } - }); + // Case 4. The success test is skipped as the client was closing from the after + // block before the it block actually finished. But we have another test in the + // KMIP section that tests the same thing and works. + context('Case 4: KMIP', metadata, function () { + it('fails with no tls', metadata, async function () { + try { + await clientEncryptionNoTls.createDataKey('kmip'); + expect.fail('it must fail with no tls'); + } catch (e) { + expect(e.originalError.message).to.include('before secure TLS connection'); + } + }); - it('fails with invalid hostnames', metadata, async function () { - try { - await clientEncryptionWithInvalidHostname.createDataKey('kmip'); - expect.fail('it must fail with invalid hostnames'); - } catch (e) { - expect(e.originalError.message).to.include('does not match certificate'); - } - }); + it('fails with expired certificates', metadata, async function () { + try { + await clientEncryptionWithTlsExpired.createDataKey('kmip'); + expect.fail('it must fail with expired certificates'); + } catch (e) { + expect(e.originalError.message).to.include('certificate has expired'); + } + }); + + it('fails with invalid hostnames', metadata, async function () { + try { + await clientEncryptionWithInvalidHostname.createDataKey('kmip'); + expect.fail('it must fail with invalid hostnames'); + } catch (e) { + expect(e.originalError.message).to.include('does not match certificate'); + } }); }); }); @@ -780,8 +641,8 @@ describe('Client Side Encryption Prose Tests', metadata, function () { customKmsProviders.gcp.endpoint = 'oauth2.googleapis.com:443'; const invalidKmsProviders = getKmsProviders(); - invalidKmsProviders.azure.identityPlatformEndpoint = 'example.com:443'; - invalidKmsProviders.gcp.endpoint = 'example.com:443'; + invalidKmsProviders.azure.identityPlatformEndpoint = 'doesnotexist.invalid:443'; + invalidKmsProviders.gcp.endpoint = 'doesnotexist.invalid:443'; return this.client.connect().then(() => { const mongodbClientEncryption = this.configuration.mongodbClientEncryption; @@ -871,7 +732,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { masterKey: { region: 'us-east-1', key: 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', - endpoint: 'example.com' + endpoint: 'doesnotexist.invalid' }, succeed: false, errorValidator: err => { @@ -913,7 +774,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { location: 'global', keyRing: 'key-ring-csfle', keyName: 'key-name-csfle', - endpoint: 'example.com:443' + endpoint: 'doesnotexist.invalid:443' }, succeed: false, errorValidator: err => { @@ -923,7 +784,40 @@ describe('Client Side Encryption Prose Tests', metadata, function () { .and.to.have.property('message') .that.matches(/Invalid KMS response/); } - } + }, + { + description: 'kmip no custom endpoint', + provider: 'kmip', + masterKey: { + keyId: '1' + }, + succeed: true, + checkAgainstInvalid: true + }, + { + description: 'kmip custom endpoint', + provider: 'kmip', + masterKey: { + keyId: '1', + endpoint: 'localhost:5698' + }, + succeed: true + }, + { + description: 'kmip invalid custom endpoint', + provider: 'kmip', + masterKey: { + keyId: '1', + endpoint: 'doesnotexist.local:5698' + }, + succeed: false, + errorValidator: err => { + expect(err) + .to.be.an.instanceOf(Error) + .and.to.have.property('message') + .that.matches(/Invalid KMS response/); + } + }, ]; testCases.forEach(testCase => { From 359ab9e3b0741b1a8e0b22584ffa07b04af41e11 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 8 Feb 2022 13:22:57 +0100 Subject: [PATCH 62/73] test(NODE-3777): fix custom endpoint tests --- .../client_side_encryption.prose.test.js | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 2b68f8db164..759e678918e 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -643,18 +643,31 @@ describe('Client Side Encryption Prose Tests', metadata, function () { const invalidKmsProviders = getKmsProviders(); invalidKmsProviders.azure.identityPlatformEndpoint = 'doesnotexist.invalid:443'; invalidKmsProviders.gcp.endpoint = 'doesnotexist.invalid:443'; + invalidKmsProviders.kmip.endpoint = 'doesnotexist.local:5698'; return this.client.connect().then(() => { const mongodbClientEncryption = this.configuration.mongodbClientEncryption; this.clientEncryption = new mongodbClientEncryption.ClientEncryption(this.client, { bson: BSON, keyVaultNamespace, - kmsProviders: customKmsProviders + kmsProviders: customKmsProviders, + tlsOptions: { + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } }); this.clientEncryptionInvalid = new mongodbClientEncryption.ClientEncryption(this.client, { keyVaultNamespace, - kmsProviders: invalidKmsProviders + kmsProviders: invalidKmsProviders, + tlsOptions: { + kmip: { + tlsCAFile: process.env.KMIP_TLS_CA_FILE, + tlsCertificateKeyFile: process.env.KMIP_TLS_CERT_FILE + } + } }); }); }); @@ -736,11 +749,11 @@ describe('Client Side Encryption Prose Tests', metadata, function () { }, succeed: false, errorValidator: err => { - // Expect this to fail with an exception with a message containing the string: "parse error" + // Expect this to fail with a network exception indicating failure to resolve "doesnotexist.invalid". expect(err) .to.be.an.instanceOf(Error) .and.to.have.property('message') - .that.matches(/parse error/); + .that.matches(/KMS request failed/); } }, { @@ -778,7 +791,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { }, succeed: false, errorValidator: err => { - // Expect this to fail with an exception with a message containing the string: "parse error" + // Expect this to fail with a network exception indicating failure to resolve "doesnotexist.invalid". expect(err) .to.be.an.instanceOf(Error) .and.to.have.property('message') @@ -815,7 +828,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { expect(err) .to.be.an.instanceOf(Error) .and.to.have.property('message') - .that.matches(/Invalid KMS response/); + .that.matches(/KMS request failed/); } }, ]; @@ -869,7 +882,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { err => { expect(err) .property('message') - .to.match(/parse error/); + .to.match(/KMS request failed/); } ) ); From bbc1336c7d8b7b684c9e46932cccc1630c6347a3 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 8 Feb 2022 13:38:02 +0100 Subject: [PATCH 63/73] fix(NODE-3777): fix lint error --- .../client-side-encryption/client_side_encryption.prose.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 759e678918e..1b4b3056de7 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -830,7 +830,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { .and.to.have.property('message') .that.matches(/KMS request failed/); } - }, + } ]; testCases.forEach(testCase => { From 3fe42a40159b241e4ddf54d8ad782cd2ccab73dc Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 8 Feb 2022 17:23:43 +0100 Subject: [PATCH 64/73] test(NODE-3777): update evg config --- .evergreen/config.yml | 6 ++++-- .evergreen/config.yml.in | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 51024d93709..553641a8d00 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -83,7 +83,7 @@ functions: ORCHESTRATION_FILE=${ORCHESTRATION_FILE} \ REQUIRE_API_VERSION=${REQUIRE_API_VERSION} \ LOAD_BALANCER=${LOAD_BALANCER} \ - sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh + bash ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh - command: expansions.update params: file: mo-expansion.yml @@ -104,7 +104,9 @@ functions: params: background: true working_dir: src - binary: bash .evergreen/run-kms-servers.sh + binary: bash + args: + - .evergreen/run-kms-servers.sh env: CLIENT_ENCRYPTION: ${CLIENT_ENCRYPTION} DRIVERS_TOOLS: ${DRIVERS_TOOLS} diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index 9527f69ca5b..e44ec4da06b 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -100,7 +100,7 @@ functions: ORCHESTRATION_FILE=${ORCHESTRATION_FILE} \ REQUIRE_API_VERSION=${REQUIRE_API_VERSION} \ LOAD_BALANCER=${LOAD_BALANCER} \ - sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh + bash ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh # run-orchestration generates expansion file with the MONGODB_URI for the cluster - command: expansions.update params: @@ -124,7 +124,9 @@ functions: params: background: true working_dir: src - binary: bash .evergreen/run-kms-servers.sh + binary: bash + args: + - .evergreen/run-kms-servers.sh env: CLIENT_ENCRYPTION: ${CLIENT_ENCRYPTION} DRIVERS_TOOLS: ${DRIVERS_TOOLS} From c8c4d2e12a28d247925d0c06527b53cef859b779 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 8 Feb 2022 18:30:08 +0100 Subject: [PATCH 65/73] test(NODE-3777): fix custom fle tests --- .evergreen/config.yml | 3 +++ .evergreen/generate_evergreen_tasks.js | 1 + 2 files changed, 4 insertions(+) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 553641a8d00..fa45aa1d8f5 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -1766,6 +1766,7 @@ tasks: VERSION: '5.0' TOPOLOGY: server AUTH: auth + - func: bootstrap kms servers - func: run custom csfle tests - name: run-custom-snappy-tests tags: @@ -1779,6 +1780,7 @@ tasks: VERSION: '5.0' TOPOLOGY: server AUTH: auth + - func: bootstrap kms servers - func: run custom snappy tests - name: run-bson-ext-test tags: @@ -1792,6 +1794,7 @@ tasks: VERSION: '5.0' TOPOLOGY: server AUTH: auth + - func: bootstrap kms servers - func: run bson-ext test vars: NODE_LTS_NAME: erbium diff --git a/.evergreen/generate_evergreen_tasks.js b/.evergreen/generate_evergreen_tasks.js index d3ac4132c0d..b5f3b1f12b8 100644 --- a/.evergreen/generate_evergreen_tasks.js +++ b/.evergreen/generate_evergreen_tasks.js @@ -668,6 +668,7 @@ const oneOffFuncAsTasks = oneOffFuncs.map(oneOffFunc => ({ AUTH: 'auth' } }, + { func: 'bootstrap kms servers' }, oneOffFunc ] })); From 8219832ceff25f54457673c2ddf437ea62183cfd Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Tue, 8 Feb 2022 21:13:53 +0100 Subject: [PATCH 66/73] test(NODE-3777): always bootstrap kms servers --- .evergreen/config.yml | 1 - .evergreen/config.yml.in | 1 - .evergreen/run-kms-servers.sh | 16 +++++++--------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index fa45aa1d8f5..20561e1eb70 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -108,7 +108,6 @@ functions: args: - .evergreen/run-kms-servers.sh env: - CLIENT_ENCRYPTION: ${CLIENT_ENCRYPTION} DRIVERS_TOOLS: ${DRIVERS_TOOLS} run tests: - command: shell.exec diff --git a/.evergreen/config.yml.in b/.evergreen/config.yml.in index e44ec4da06b..184bac4402c 100644 --- a/.evergreen/config.yml.in +++ b/.evergreen/config.yml.in @@ -128,7 +128,6 @@ functions: args: - .evergreen/run-kms-servers.sh env: - CLIENT_ENCRYPTION: ${CLIENT_ENCRYPTION} DRIVERS_TOOLS: ${DRIVERS_TOOLS} "run tests": - command: shell.exec diff --git a/.evergreen/run-kms-servers.sh b/.evergreen/run-kms-servers.sh index dbbbffa4a05..76ef6ac258e 100644 --- a/.evergreen/run-kms-servers.sh +++ b/.evergreen/run-kms-servers.sh @@ -1,9 +1,7 @@ -if [ -n "${CLIENT_ENCRYPTION}" ]; then - cd ${DRIVERS_TOOLS}/.evergreen/csfle - . ./activate_venv.sh - # by default it always runs on port 5698 - ./kmstlsvenv/bin/python3 -u kms_kmip_server.py & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & - ./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & -fi +cd ${DRIVERS_TOOLS}/.evergreen/csfle +. ./activate_venv.sh +# by default it always runs on port 5698 +./kmstlsvenv/bin/python3 -u kms_kmip_server.py & +./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 & +./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 & +./kmstlsvenv/bin/python3 -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8002 --require_client_cert & From dc29d39f374ac01a0e540207bc5853610ba76435 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 9 Feb 2022 13:18:10 +0100 Subject: [PATCH 67/73] test(NODE-3777): skip entire prose test when no applicable --- .../client_side_encryption.prose.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 1b4b3056de7..36c3a42be51 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -45,6 +45,10 @@ const metadata = { // Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk // TODO: NODE-3927 - these cannot run in lb mode but are not skipping based on metadata. describe('Client Side Encryption Prose Tests', metadata, function () { + // https://github.com/mochajs/mocha/issues/2456 + if (process.env.LOAD_BALANCER || !process.env.CSFLE_KMS_PROVIDERS) { + this.skip(); + } const dataDbName = 'db'; const dataCollName = 'coll'; const dataNamespace = `${dataDbName}.${dataCollName}`; @@ -83,7 +87,6 @@ describe('Client Side Encryption Prose Tests', metadata, function () { let clientEncryptionWithInvalidHostname; before(async function () { - if (process.env.LOAD_BALANCER) this.skip(); tlsCaOptions = { aws: { tlsCAFile: process.env.KMIP_TLS_CA_FILE @@ -165,7 +168,6 @@ describe('Client Side Encryption Prose Tests', metadata, function () { }); beforeEach(async function () { - if (process.env.LOAD_BALANCER) this.skip(); await clientNoTls.connect(); await clientWithTls.connect(); await clientWithTlsExpired.connect(); From 1694bba5edf5897517d939690e6bbe85e65e4d05 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 9 Feb 2022 13:50:21 +0100 Subject: [PATCH 68/73] test(NODE-3777): move csfle to manual --- package.json | 2 +- .../client-side-encryption/.gitkeep | 0 .../client_side_encryption.corpus.spec.test.js | 0 .../client_side_encryption.prose.deadlock.js | 2 +- .../client_side_encryption.prose.test.js | 7 +------ .../client_side_encryption.spec.test.js | 0 .../client-side-encryption/driver.test.js | 0 7 files changed, 3 insertions(+), 8 deletions(-) rename test/{integration => manual}/client-side-encryption/.gitkeep (100%) rename test/{integration => manual}/client-side-encryption/client_side_encryption.corpus.spec.test.js (100%) rename test/{integration => manual}/client-side-encryption/client_side_encryption.prose.deadlock.js (99%) rename test/{integration => manual}/client-side-encryption/client_side_encryption.prose.test.js (99%) rename test/{integration => manual}/client-side-encryption/client_side_encryption.spec.test.js (100%) rename test/{integration => manual}/client-side-encryption/driver.test.js (100%) diff --git a/package.json b/package.json index 41bff208ab8..429d93cf047 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "check:tls": "mocha --config test/manual/mocharc.json test/manual/tls_support.test.js", "check:ldap": "mocha --config test/manual/mocharc.json test/manual/ldap.test.js", "check:socks5": "mocha --config test/manual/mocharc.json test/manual/socks5.test.ts", - "check:csfle": "mocha --config test/mocha_mongodb.json test/integration/client-side-encryption", + "check:csfle": "mocha --config test/mocha_mongodb.json test/manual/client-side-encryption", "check:snappy": "mocha test/unit/assorted/snappy.test.js", "prepare": "node etc/prepare.js", "release": "standard-version -i HISTORY.md", diff --git a/test/integration/client-side-encryption/.gitkeep b/test/manual/client-side-encryption/.gitkeep similarity index 100% rename from test/integration/client-side-encryption/.gitkeep rename to test/manual/client-side-encryption/.gitkeep diff --git a/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js b/test/manual/client-side-encryption/client_side_encryption.corpus.spec.test.js similarity index 100% rename from test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js rename to test/manual/client-side-encryption/client_side_encryption.corpus.spec.test.js diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.deadlock.js b/test/manual/client-side-encryption/client_side_encryption.prose.deadlock.js similarity index 99% rename from test/integration/client-side-encryption/client_side_encryption.prose.deadlock.js rename to test/manual/client-side-encryption/client_side_encryption.prose.deadlock.js index 7d36bb5fb63..cab8ad276a4 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.deadlock.js +++ b/test/manual/client-side-encryption/client_side_encryption.prose.deadlock.js @@ -2,7 +2,7 @@ const BSON = require('bson'); const { expect } = require('chai'); -const { dropCollection } = require('../shared'); +const { dropCollection } = require('../../integration/shared'); const util = require('util'); const fs = require('fs'); const path = require('path'); diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/manual/client-side-encryption/client_side_encryption.prose.test.js similarity index 99% rename from test/integration/client-side-encryption/client_side_encryption.prose.test.js rename to test/manual/client-side-encryption/client_side_encryption.prose.test.js index 36c3a42be51..ef8bcd08d67 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/manual/client-side-encryption/client_side_encryption.prose.test.js @@ -43,12 +43,7 @@ const metadata = { // .. code:: javascript // Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk -// TODO: NODE-3927 - these cannot run in lb mode but are not skipping based on metadata. describe('Client Side Encryption Prose Tests', metadata, function () { - // https://github.com/mochajs/mocha/issues/2456 - if (process.env.LOAD_BALANCER || !process.env.CSFLE_KMS_PROVIDERS) { - this.skip(); - } const dataDbName = 'db'; const dataCollName = 'coll'; const dataNamespace = `${dataDbName}.${dataCollName}`; @@ -56,7 +51,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { const keyVaultCollName = 'datakeys'; const keyVaultNamespace = `${keyVaultDbName}.${keyVaultCollName}`; - const shared = require('../shared'); + const shared = require('../../integration/shared'); const dropCollection = shared.dropCollection; const APMEventCollector = shared.APMEventCollector; diff --git a/test/integration/client-side-encryption/client_side_encryption.spec.test.js b/test/manual/client-side-encryption/client_side_encryption.spec.test.js similarity index 100% rename from test/integration/client-side-encryption/client_side_encryption.spec.test.js rename to test/manual/client-side-encryption/client_side_encryption.spec.test.js diff --git a/test/integration/client-side-encryption/driver.test.js b/test/manual/client-side-encryption/driver.test.js similarity index 100% rename from test/integration/client-side-encryption/driver.test.js rename to test/manual/client-side-encryption/driver.test.js From 063596985d8e6efaf0bf238b3144e552b1e4424a Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 9 Feb 2022 14:16:38 +0100 Subject: [PATCH 69/73] test(NODE-3777): csfle runs noauth --- .evergreen/config.yml | 3 --- .evergreen/generate_evergreen_tasks.js | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 20561e1eb70..8b804a61a8c 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -1764,7 +1764,6 @@ tasks: vars: VERSION: '5.0' TOPOLOGY: server - AUTH: auth - func: bootstrap kms servers - func: run custom csfle tests - name: run-custom-snappy-tests @@ -1778,7 +1777,6 @@ tasks: vars: VERSION: '5.0' TOPOLOGY: server - AUTH: auth - func: bootstrap kms servers - func: run custom snappy tests - name: run-bson-ext-test @@ -1792,7 +1790,6 @@ tasks: vars: VERSION: '5.0' TOPOLOGY: server - AUTH: auth - func: bootstrap kms servers - func: run bson-ext test vars: diff --git a/.evergreen/generate_evergreen_tasks.js b/.evergreen/generate_evergreen_tasks.js index b5f3b1f12b8..2e7de80a91e 100644 --- a/.evergreen/generate_evergreen_tasks.js +++ b/.evergreen/generate_evergreen_tasks.js @@ -664,8 +664,7 @@ const oneOffFuncAsTasks = oneOffFuncs.map(oneOffFunc => ({ func: 'bootstrap mongo-orchestration', vars: { VERSION: '5.0', - TOPOLOGY: 'server', - AUTH: 'auth' + TOPOLOGY: 'server' } }, { func: 'bootstrap kms servers' }, From 2f1c62af05b663a479d548dbfe6096a60d4ba204 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 9 Feb 2022 14:42:29 +0100 Subject: [PATCH 70/73] test(NODE-3777): split out csfle config --- .evergreen/config.yml | 24 +++++++++++------------ .evergreen/generate_evergreen_tasks.js | 27 +++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 8b804a61a8c..967c691a5fb 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -1753,7 +1753,7 @@ tasks: vars: NODE_LTS_NAME: fermium - func: run mongosh integration tests - - name: run-custom-csfle-tests + - name: run-custom-snappy-tests tags: - run-custom-dependency-tests commands: @@ -1764,9 +1764,9 @@ tasks: vars: VERSION: '5.0' TOPOLOGY: server - - func: bootstrap kms servers - - func: run custom csfle tests - - name: run-custom-snappy-tests + AUTH: auth + - func: run custom snappy tests + - name: run-bson-ext-test tags: - run-custom-dependency-tests commands: @@ -1777,9 +1777,11 @@ tasks: vars: VERSION: '5.0' TOPOLOGY: server - - func: bootstrap kms servers - - func: run custom snappy tests - - name: run-bson-ext-test + AUTH: auth + - func: run bson-ext test + vars: + NODE_LTS_NAME: erbium + - name: run-custom-csfle-tests tags: - run-custom-dependency-tests commands: @@ -1788,12 +1790,10 @@ tasks: NODE_LTS_NAME: erbium - func: bootstrap mongo-orchestration vars: - VERSION: '5.0' + VERSION: latest TOPOLOGY: server - func: bootstrap kms servers - - func: run bson-ext test - vars: - NODE_LTS_NAME: erbium + - func: run custom csfle tests - name: test-latest-server-noauth tags: - latest @@ -2343,9 +2343,9 @@ buildvariants: display_name: Custom Dependency Version Test run_on: ubuntu1804-large tasks: - - run-custom-csfle-tests - run-custom-snappy-tests - run-bson-ext-test + - run-custom-csfle-tests - name: ubuntu1804-test-serverless display_name: Serverless Test run_on: ubuntu1804-test diff --git a/.evergreen/generate_evergreen_tasks.js b/.evergreen/generate_evergreen_tasks.js index 2e7de80a91e..f2e244429a9 100644 --- a/.evergreen/generate_evergreen_tasks.js +++ b/.evergreen/generate_evergreen_tasks.js @@ -640,7 +640,6 @@ BUILD_VARIANTS.push({ }); const oneOffFuncs = [ - { func: 'run custom csfle tests' }, { func: 'run custom snappy tests' }, { func: 'run bson-ext test', @@ -664,14 +663,36 @@ const oneOffFuncAsTasks = oneOffFuncs.map(oneOffFunc => ({ func: 'bootstrap mongo-orchestration', vars: { VERSION: '5.0', - TOPOLOGY: 'server' + TOPOLOGY: 'server', + AUTH: 'auth' } }, - { func: 'bootstrap kms servers' }, oneOffFunc ] })); +oneOffFuncAsTasks.push({ + name: 'run-custom-csfle-tests', + tags: ['run-custom-dependency-tests'], + commands: [ + { + func: 'install dependencies', + vars: { + NODE_LTS_NAME: LOWEST_LTS + } + }, + { + func: 'bootstrap mongo-orchestration', + vars: { + VERSION: 'latest', + TOPOLOGY: 'server' + } + }, + { func: 'bootstrap kms servers' }, + { func: 'run custom csfle tests' } + ] +}); + // TODO NODE-3897 - generate combined coverage report const coverageTask = { name: 'download and merge coverage'.split(' ').join('-'), From 2c2dbd4495b3aabcaaa0f6084b155e5ac3ada419 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 9 Feb 2022 18:22:12 +0100 Subject: [PATCH 71/73] test(NODE-3777): move csfle back to integration --- package.json | 2 +- .../client-side-encryption/.gitkeep | 0 ...client_side_encryption.corpus.spec.test.js | 0 .../client_side_encryption.prose.deadlock.js | 0 .../client_side_encryption.prose.test.js | 91 +++++++------------ .../client_side_encryption.spec.test.js | 0 .../client-side-encryption/driver.test.js | 0 7 files changed, 36 insertions(+), 57 deletions(-) rename test/{manual => integration}/client-side-encryption/.gitkeep (100%) rename test/{manual => integration}/client-side-encryption/client_side_encryption.corpus.spec.test.js (100%) rename test/{manual => integration}/client-side-encryption/client_side_encryption.prose.deadlock.js (100%) rename test/{manual => integration}/client-side-encryption/client_side_encryption.prose.test.js (96%) rename test/{manual => integration}/client-side-encryption/client_side_encryption.spec.test.js (100%) rename test/{manual => integration}/client-side-encryption/driver.test.js (100%) diff --git a/package.json b/package.json index 429d93cf047..41bff208ab8 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "check:tls": "mocha --config test/manual/mocharc.json test/manual/tls_support.test.js", "check:ldap": "mocha --config test/manual/mocharc.json test/manual/ldap.test.js", "check:socks5": "mocha --config test/manual/mocharc.json test/manual/socks5.test.ts", - "check:csfle": "mocha --config test/mocha_mongodb.json test/manual/client-side-encryption", + "check:csfle": "mocha --config test/mocha_mongodb.json test/integration/client-side-encryption", "check:snappy": "mocha test/unit/assorted/snappy.test.js", "prepare": "node etc/prepare.js", "release": "standard-version -i HISTORY.md", diff --git a/test/manual/client-side-encryption/.gitkeep b/test/integration/client-side-encryption/.gitkeep similarity index 100% rename from test/manual/client-side-encryption/.gitkeep rename to test/integration/client-side-encryption/.gitkeep diff --git a/test/manual/client-side-encryption/client_side_encryption.corpus.spec.test.js b/test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js similarity index 100% rename from test/manual/client-side-encryption/client_side_encryption.corpus.spec.test.js rename to test/integration/client-side-encryption/client_side_encryption.corpus.spec.test.js diff --git a/test/manual/client-side-encryption/client_side_encryption.prose.deadlock.js b/test/integration/client-side-encryption/client_side_encryption.prose.deadlock.js similarity index 100% rename from test/manual/client-side-encryption/client_side_encryption.prose.deadlock.js rename to test/integration/client-side-encryption/client_side_encryption.prose.deadlock.js diff --git a/test/manual/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js similarity index 96% rename from test/manual/client-side-encryption/client_side_encryption.prose.test.js rename to test/integration/client-side-encryption/client_side_encryption.prose.test.js index ef8bcd08d67..3ddc78e6209 100644 --- a/test/manual/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -162,22 +162,6 @@ describe('Client Side Encryption Prose Tests', metadata, function () { ); }); - beforeEach(async function () { - await clientNoTls.connect(); - await clientWithTls.connect(); - await clientWithTlsExpired.connect(); - await clientWithInvalidHostname.connect(); - await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); - await dropCollection(clientNoTls.db(keyVaultDbName), keyVaultCollName); - }); - - afterEach(async function () { - await clientNoTls.close(); - await clientWithTls.close(); - await clientWithTlsExpired.close(); - await clientWithInvalidHostname.close(); - }); - // Case 1. context('Case 1: AWS', metadata, function () { const masterKey = { @@ -188,40 +172,39 @@ describe('Client Side Encryption Prose Tests', metadata, function () { const masterKeyExpired = { ...masterKey, endpoint: '127.0.0.1:8000' }; const masterKeyInvalidHostname = { ...masterKey, endpoint: '127.0.0.1:8001' }; - it('fails with no tls', metadata, async function () { + it('fails with various invalid tls options', metadata, async function () { try { + await clientNoTls.connect(); await clientEncryptionNoTls.createDataKey('aws', { masterKey }); expect.fail('it must fail with no tls'); } catch (e) { expect(e.originalError.message).to.include('certificate required'); + await clientNoTls.close(); } - }); - - it('passes with tls but fails to parse', metadata, async function () { try { + await clientWithTls.connect(); await clientEncryptionWithTls.createDataKey('aws', { masterKey }); expect.fail('it must fail to parse response'); } catch (e) { + await clientWithTls.close(); expect(e.message).to.include('parse error'); } - }); - - it('fails with expired certificates', metadata, async function () { try { + await clientWithTlsExpired.connect(); await clientEncryptionWithTlsExpired.createDataKey('aws', { masterKeyExpired }); expect.fail('it must fail with invalid certificate'); } catch (e) { + await clientWithTlsExpired.close(); expect(e.message).to.include('expected UTF-8 key'); } - }); - - it('fails with invalid hostnames', metadata, async function () { try { + await clientWithInvalidHostname.connect(); await clientEncryptionWithInvalidHostname.createDataKey('aws', { masterKeyInvalidHostname }); expect.fail('it must fail with invalid hostnames'); } catch (e) { + await clientWithInvalidHostname.close(); expect(e.message).to.include('expected UTF-8 key'); } }); @@ -234,38 +217,37 @@ describe('Client Side Encryption Prose Tests', metadata, function () { keyName: 'foo' }; - it('fails with no tls', metadata, async function () { + it('fails with various invalid tls options', metadata, async function () { try { + await clientNoTls.connect(); await clientEncryptionNoTls.createDataKey('azure', { masterKey }); expect.fail('it must fail with no tls'); } catch (e) { + await clientNoTls.close(); expect(e.originalError.message).to.include('certificate required'); } - }); - - it('fails with invalid host', metadata, async function () { try { + await clientWithTls.connect(); await clientEncryptionWithTls.createDataKey('azure', { masterKey }); expect.fail('it must fail with invalid host'); } catch (e) { + await clientWithTls.close(); expect(e.message).to.include('HTTP status=404'); } - }); - - it('fails with expired certificates', metadata, async function () { try { + await clientWithTlsExpired.connect(); await clientEncryptionWithTlsExpired.createDataKey('azure', { masterKey }); expect.fail('it must fail with expired certificates'); } catch (e) { + await clientWithTlsExpired.close(); expect(e.originalError.message).to.include('certificate has expired'); } - }); - - it('fails with invalid hostnames', metadata, async function () { try { + await clientWithInvalidHostname.connect(); await clientEncryptionWithInvalidHostname.createDataKey('azure', { masterKey }); expect.fail('it must fail with invalid hostnames'); } catch (e) { + await clientWithInvalidHostname.close(); expect(e.originalError.message).to.include('does not match certificate'); } }); @@ -280,70 +262,67 @@ describe('Client Side Encryption Prose Tests', metadata, function () { keyName: 'foo' }; - it('fails with no tls', metadata, async function () { + it('fails with various invalid tls options', metadata, async function () { try { + await clientNoTls.connect(); await clientEncryptionNoTls.createDataKey('gcp', { masterKey }); expect.fail('it must fail with no tls'); } catch (e) { + await clientNoTls.close(); expect(e.originalError.message).to.include('certificate required'); } - }); - - it('fails with invalid host', metadata, async function () { try { + await clientWithTls.connect(); await clientEncryptionWithTls.createDataKey('gcp', { masterKey }); expect.fail('it must fail with invalid host'); } catch (e) { + await clientWithTls.close(); expect(e.message).to.include('HTTP status=404'); } - }); - - it('fails with expired certificates', metadata, async function () { try { + await clientWithTlsExpired.connect(); await clientEncryptionWithTlsExpired.createDataKey('gcp', { masterKey }); expect.fail('it must fail with expired certificates'); } catch (e) { + await clientWithTlsExpired.close(); expect(e.originalError.message).to.include('certificate has expired'); } - }); - - it('fails with invalid hostnames', metadata, async function () { try { + await clientWithInvalidHostname.connect(); await clientEncryptionWithInvalidHostname.createDataKey('gcp', { masterKey }); expect.fail('it must fail with invalid hostnames'); } catch (e) { + await clientWithInvalidHostname.close(); expect(e.originalError.message).to.include('does not match certificate'); } }); }); - // Case 4. The success test is skipped as the client was closing from the after - // block before the it block actually finished. But we have another test in the - // KMIP section that tests the same thing and works. + // Case 4. context('Case 4: KMIP', metadata, function () { - it('fails with no tls', metadata, async function () { + it('fails with various invalid tls options', metadata, async function () { try { + await clientNoTls.connect(); await clientEncryptionNoTls.createDataKey('kmip'); expect.fail('it must fail with no tls'); } catch (e) { + await clientNoTls.close(); expect(e.originalError.message).to.include('before secure TLS connection'); } - }); - - it('fails with expired certificates', metadata, async function () { try { + await clientWithTlsExpired.connect(); await clientEncryptionWithTlsExpired.createDataKey('kmip'); expect.fail('it must fail with expired certificates'); } catch (e) { + await clientWithTlsExpired.close(); expect(e.originalError.message).to.include('certificate has expired'); } - }); - - it('fails with invalid hostnames', metadata, async function () { try { + await clientWithInvalidHostname.connect(); await clientEncryptionWithInvalidHostname.createDataKey('kmip'); expect.fail('it must fail with invalid hostnames'); } catch (e) { + await clientWithInvalidHostname.close(); expect(e.originalError.message).to.include('does not match certificate'); } }); diff --git a/test/manual/client-side-encryption/client_side_encryption.spec.test.js b/test/integration/client-side-encryption/client_side_encryption.spec.test.js similarity index 100% rename from test/manual/client-side-encryption/client_side_encryption.spec.test.js rename to test/integration/client-side-encryption/client_side_encryption.spec.test.js diff --git a/test/manual/client-side-encryption/driver.test.js b/test/integration/client-side-encryption/driver.test.js similarity index 100% rename from test/manual/client-side-encryption/driver.test.js rename to test/integration/client-side-encryption/driver.test.js From f51396c8478f66f8f4b794c94778fa46b9555c47 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 9 Feb 2022 18:43:54 +0100 Subject: [PATCH 72/73] test(NODE-3777): install csfle for all test runs --- .evergreen/run-tests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index abc801a4c97..642c2f6ab96 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -41,13 +41,13 @@ if [[ -z "${CLIENT_ENCRYPTION}" ]]; then unset AWS_ACCESS_KEY_ID; unset AWS_SECRET_ACCESS_KEY; else - npm install mongodb-client-encryption@">=2.0.0-beta.3" pip install --upgrade boto3 - # Get access to the AWS temporary credentials: echo "adding temporary AWS credentials to environment" # CSFLE_AWS_TEMP_ACCESS_KEY_ID, CSFLE_AWS_TEMP_SECRET_ACCESS_KEY, CSFLE_AWS_TEMP_SESSION_TOKEN . $DRIVERS_TOOLS/.evergreen/csfle/set-temp-creds.sh fi +npm install mongodb-client-encryption@">=2.0.0-beta.3" + AUTH=$AUTH SINGLE_MONGOS_LB_URI=${SINGLE_MONGOS_LB_URI} MULTI_MONGOS_LB_URI=${MULTI_MONGOS_LB_URI} MONGODB_API_VERSION=${MONGODB_API_VERSION} MONGODB_UNIFIED_TOPOLOGY=${UNIFIED} MONGODB_URI=${MONGODB_URI} LOAD_BALANCER=${LOAD_BALANCER} npm run ${TEST_NPM_SCRIPT} From 207e6340796bfa945136f4d6164db375c2624c0e Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Wed, 9 Feb 2022 19:07:19 +0100 Subject: [PATCH 73/73] test(NODE-3777): skip kmip test with auth --- .evergreen/run-bson-ext-test.sh | 1 + .../client_side_encryption.prose.test.js | 4 ++-- .../client_side_encryption.spec.test.js | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.evergreen/run-bson-ext-test.sh b/.evergreen/run-bson-ext-test.sh index 7e66583c6cb..ffa258d79cc 100755 --- a/.evergreen/run-bson-ext-test.sh +++ b/.evergreen/run-bson-ext-test.sh @@ -23,6 +23,7 @@ fi # run tests echo "Running $AUTH tests over $SSL, connecting to $MONGODB_URI" +npm install mongodb-client-encryption@">=2.0.0-beta.3" npm install bson-ext export MONGODB_API_VERSION=${MONGODB_API_VERSION} diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.test.js b/test/integration/client-side-encryption/client_side_encryption.prose.test.js index 3ddc78e6209..14c6eb1a3e4 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.prose.test.js @@ -66,7 +66,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { * - Create client encryption expired * - Create client encryption invalid hostname */ - context('KMS TLS Options Tests', metadata, async function () { + context('KMS TLS Options Tests', metadata, function () { let tlsCaOptions; let clientNoTlsOptions; let clientWithTlsOptions; @@ -81,7 +81,7 @@ describe('Client Side Encryption Prose Tests', metadata, function () { let clientEncryptionWithTlsExpired; let clientEncryptionWithInvalidHostname; - before(async function () { + before(function () { tlsCaOptions = { aws: { tlsCAFile: process.env.KMIP_TLS_CA_FILE diff --git a/test/integration/client-side-encryption/client_side_encryption.spec.test.js b/test/integration/client-side-encryption/client_side_encryption.spec.test.js index 05a398440c6..fa2c3ff16c6 100644 --- a/test/integration/client-side-encryption/client_side_encryption.spec.test.js +++ b/test/integration/client-side-encryption/client_side_encryption.spec.test.js @@ -48,7 +48,8 @@ const skippedAuthTests = [ 'insertMany with encryption', 'insertOne with encryption', 'findOneAndDelete with deterministic encryption', - '$unset works with an encrypted field' + '$unset works with an encrypted field', + 'Insert a document with auto encryption using KMIP KMS provider' ]; const SKIPPED_TESTS = new Set(isAuthEnabled ? skippedAuthTests : []);