summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2022-11-16 11:15:25 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-11-21 16:58:31 +0000
commitc29635f02bfcd6e27b6b20debf66ba1e7fdfc171 (patch)
tree771e307e8c479ddb8bb2db5aeabdd0466d289496
parentc0cc8aba2740f0f345bd2387759188e2f1a35612 (diff)
downloadmongo-c29635f02bfcd6e27b6b20debf66ba1e7fdfc171.tar.gz
SERVER-71318 Remove remote KMS specific code and related tests
-rw-r--r--etc/evergreen_yml_components/definitions.yml11
-rw-r--r--evergreen/functions/aws_test_credentials_load.sh15
-rw-r--r--jstests/client_encrypt/fle_auto_decrypt.js1
-rw-r--r--jstests/client_encrypt/fle_aws_faults.js164
-rw-r--r--jstests/client_encrypt/fle_azure_faults.js175
-rw-r--r--jstests/client_encrypt/fle_encrypt_decrypt_shell.js14
-rw-r--r--jstests/client_encrypt/fle_gcp_faults.js190
-rw-r--r--jstests/client_encrypt/fle_key_faults.js14
-rw-r--r--jstests/client_encrypt/fle_keys.js27
-rw-r--r--jstests/client_encrypt/fle_valid_fle_options.js17
-rw-r--r--jstests/client_encrypt/lib/fle_command_line_explicit_encryption.js8
-rw-r--r--jstests/client_encrypt/lib/kms_http_common.py148
-rw-r--r--jstests/client_encrypt/lib/kms_http_control.py52
-rwxr-xr-xjstests/client_encrypt/lib/kms_http_server.py244
-rwxr-xr-xjstests/client_encrypt/lib/kms_http_server_azure.py239
-rwxr-xr-xjstests/client_encrypt/lib/kms_http_server_gcp.py240
-rw-r--r--jstests/client_encrypt/lib/mock_kms.js188
-rw-r--r--src/mongo/shell/SConscript24
-rw-r--r--src/mongo/shell/encrypted_dbclient_base.cpp32
-rw-r--r--src/mongo/shell/encrypted_dbclient_base.h1
-rw-r--r--src/mongo/shell/encrypted_shell_options.h45
-rw-r--r--src/mongo/shell/fle_shell_options.idl37
-rw-r--r--src/mongo/shell/kms.cpp14
-rw-r--r--src/mongo/shell/kms.h10
-rw-r--r--src/mongo/shell/kms.idl213
-rw-r--r--src/mongo/shell/kms_aws.cpp322
-rw-r--r--src/mongo/shell/kms_azure.cpp301
-rw-r--r--src/mongo/shell/kms_gcp.cpp339
-rw-r--r--src/mongo/shell/kms_local.cpp6
-rw-r--r--src/mongo/shell/kms_network.cpp211
-rw-r--r--src/mongo/shell/kms_network.h125
31 files changed, 41 insertions, 3386 deletions
diff --git a/etc/evergreen_yml_components/definitions.yml b/etc/evergreen_yml_components/definitions.yml
index ca3e61288aa..a77795ea700 100644
--- a/etc/evergreen_yml_components/definitions.yml
+++ b/etc/evergreen_yml_components/definitions.yml
@@ -1394,15 +1394,6 @@ functions:
args:
- "./src/evergreen/jepsen_test_fail.sh"
- "load aws test credentials":
- - *f_expansions_write
- - command: subprocess.exec
- params:
- binary: bash
- silent: true
- args:
- - "./src/evergreen/functions/aws_test_credentials_load.sh"
-
"setup jstestfuzz":
- *f_expansions_write
- command: subprocess.exec
@@ -6457,7 +6448,6 @@ tasks:
tags: ["encrypt", "patch_build"]
commands:
- func: "do setup"
- - func: "load aws test credentials"
- func: "run tests"
vars:
resmoke_jobs_max: 1
@@ -6467,7 +6457,6 @@ tasks:
tags: ["encrypt", "patch_build"]
commands:
- func: "do setup"
- - func: "load aws test credentials"
- func: "run tests"
- <<: *task_template
diff --git a/evergreen/functions/aws_test_credentials_load.sh b/evergreen/functions/aws_test_credentials_load.sh
deleted file mode 100644
index 289c125f9b5..00000000000
--- a/evergreen/functions/aws_test_credentials_load.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)"
-. "$DIR/../prelude.sh"
-
-cd src
-
-set -o errexit
-echo "const AWS_KMS_SECRET_ID = '${aws_kms_access_key_id}';" >> src/mongo/db/modules/enterprise/jstests/fle/lib/aws_secrets.js
-echo "const AWS_KMS_SECRET_KEY = '${aws_kms_secret_access_key}';" >> src/mongo/db/modules/enterprise/jstests/fle/lib/aws_secrets.js
-
-echo "const KMS_GCP_EMAIL = '${kms_gcp_email}'; " >> src/mongo/db/modules/enterprise/jstests/fle/lib/aws_secrets.js
-echo "const KMS_GCP_PRIVATEKEY = '${kms_gcp_privatekey}'; " >> src/mongo/db/modules/enterprise/jstests/fle/lib/aws_secrets.js
-
-echo "const KMS_AZURE_TENANT_ID = '${kms_azure_tenant_id}';" >> src/mongo/db/modules/enterprise/jstests/fle/lib/aws_secrets.js
-echo "const KMS_AZURE_CLIENT_ID = '${kms_azure_client_id}';" >> src/mongo/db/modules/enterprise/jstests/fle/lib/aws_secrets.js
-echo "const KMS_AZURE_CLIENT_SECRET = '${kms_azure_client_secret}';" >> src/mongo/db/modules/enterprise/jstests/fle/lib/aws_secrets.js
diff --git a/jstests/client_encrypt/fle_auto_decrypt.js b/jstests/client_encrypt/fle_auto_decrypt.js
index b74a2ad421a..650125e0fb7 100644
--- a/jstests/client_encrypt/fle_auto_decrypt.js
+++ b/jstests/client_encrypt/fle_auto_decrypt.js
@@ -1,7 +1,6 @@
// Test to ensure that the client community shell auto decrypts an encrypted field
// stored in the database if it has the correct credentials.
-load("jstests/client_encrypt/lib/mock_kms.js");
load('jstests/ssl/libs/ssl_helpers.js');
(function() {
diff --git a/jstests/client_encrypt/fle_aws_faults.js b/jstests/client_encrypt/fle_aws_faults.js
deleted file mode 100644
index 28b06a55bee..00000000000
--- a/jstests/client_encrypt/fle_aws_faults.js
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- * Verify the AWS KMS implementation can handle a buggy KMS.
- */
-
-load("jstests/client_encrypt/lib/mock_kms.js");
-load('jstests/ssl/libs/ssl_helpers.js');
-
-(function() {
-"use strict";
-
-const x509_options = {
- sslMode: "requireSSL",
- sslPEMKeyFile: SERVER_CERT,
- sslCAFile: CA_CERT
-};
-
-const randomAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Random";
-
-const conn = MongoRunner.runMongod(x509_options);
-const test = conn.getDB("test");
-const collection = test.coll;
-
-function runKMS(mock_kms, func) {
- mock_kms.start();
-
- const awsKMS = {
- accessKeyId: "access",
- secretAccessKey: "secret",
- url: mock_kms.getURL(),
- };
-
- const clientSideFLEOptions = {
- kmsProviders: {
- aws: awsKMS,
- },
- keyVaultNamespace: "test.coll",
- schemaMap: {}
- };
-
- const shell = Mongo(conn.host, clientSideFLEOptions);
- const cleanCacheShell = Mongo(conn.host, clientSideFLEOptions);
-
- collection.drop();
-
- func(shell, cleanCacheShell);
-
- mock_kms.stop();
-}
-
-function testWrongKeyType() {
- const awsKMS = {accessKeyId: "access", secretAccessKey: "secret", url: "localhost:8000"};
-
- const clientSideFLEOptions = {
- kmsProviders: {
- aws: awsKMS,
- },
- keyVaultNamespace: "test.coll",
- schemaMap: {}
- };
-
- const shell = Mongo(conn.host, clientSideFLEOptions);
-
- collection.drop();
-
- const keyVault = shell.getKeyVault();
-
- assert.throws(() => keyVault.createKey(
- "aws",
- {"region": "us-east-1", "key": "arn:aws:kms:us-east-1:fake:fake:fake"},
- ["mongoKey"]));
-}
-
-testWrongKeyType();
-
-function testBadEncryptResult(fault) {
- const mock_kms = new MockKMSServerAWS(fault, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
-
- assert.throws(
- () => keyVault.createKey("aws", "arn:aws:kms:us-east-1:fake:fake:fake", ["mongoKey"]));
- assert.eq(keyVault.getKeys("mongoKey").toArray().length, 0);
- });
-}
-
-testBadEncryptResult(FAULT_ENCRYPT);
-testBadEncryptResult(FAULT_ENCRYPT_WRONG_FIELDS);
-testBadEncryptResult(FAULT_ENCRYPT_BAD_BASE64);
-
-function testBadEncryptError() {
- const mock_kms = new MockKMSServerAWS(FAULT_ENCRYPT_CORRECT_FORMAT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
-
- let error = assert.throws(
- () => keyVault.createKey("aws", "arn:aws:kms:us-east-1:fake:fake:fake", ["mongoKey"]));
- assert.commandFailedWithCode(error, [51224]);
- assert.eq(error,
- "Error: AWS KMS failed to encrypt: NotFoundException : Error encrypting message");
- });
-}
-
-testBadEncryptError();
-
-function testBadDecryptResult(fault) {
- const mock_kms = new MockKMSServerAWS(fault, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
- const keyId =
- keyVault.createKey("aws", "arn:aws:kms:us-east-1:fake:fake:fake", ["mongoKey"]);
- const str = "mongo";
- assert.throws(() => {
- const encStr = shell.getClientEncryption().encrypt(keyId, str, randomAlgorithm);
- });
- });
-}
-
-testBadDecryptResult(FAULT_DECRYPT);
-
-function testBadDecryptKeyResult(fault) {
- const mock_kms = new MockKMSServerAWS(fault, true);
-
- runKMS(mock_kms, (shell, cleanCacheShell) => {
- const keyVault = shell.getKeyVault();
-
- keyVault.createKey("aws", "arn:aws:kms:us-east-1:fake:fake:fake", ["mongoKey"]);
- const keyId = keyVault.getKeys("mongoKey").toArray()[0]._id;
- const str = "mongo";
- const encStr = shell.getClientEncryption().encrypt(keyId, str, randomAlgorithm);
-
- mock_kms.enableFaults();
-
- assert.throws(() => {
- var str = cleanCacheShell.decrypt(encStr);
- });
- });
-}
-
-testBadDecryptKeyResult(FAULT_DECRYPT_WRONG_KEY);
-
-function testBadDecryptError() {
- const mock_kms = new MockKMSServerAWS(FAULT_DECRYPT_CORRECT_FORMAT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
- keyVault.createKey("aws", "arn:aws:kms:us-east-1:fake:fake:fake", ["mongoKey"]);
- const keyId = keyVault.getKeys("mongoKey").toArray()[0]._id;
- const str = "mongo";
- let error = assert.throws(() => {
- const encStr = shell.getClientEncryption().encrypt(keyId, str, randomAlgorithm);
- });
- assert.commandFailedWithCode(error, [51225]);
- assert.eq(error,
- "Error: AWS KMS failed to decrypt: NotFoundException : Error decrypting message");
- });
-}
-
-testBadDecryptError();
-
-MongoRunner.stopMongod(conn);
-}()); \ No newline at end of file
diff --git a/jstests/client_encrypt/fle_azure_faults.js b/jstests/client_encrypt/fle_azure_faults.js
deleted file mode 100644
index dfcf121844a..00000000000
--- a/jstests/client_encrypt/fle_azure_faults.js
+++ /dev/null
@@ -1,175 +0,0 @@
-/**
- * Verify the Azure KMS implementation can handle a buggy KMS.
- */
-
-load("jstests/client_encrypt/lib/mock_kms.js");
-load('jstests/ssl/libs/ssl_helpers.js');
-
-(function() {
-"use strict";
-
-const x509_options = {
- sslMode: "requireSSL",
- sslPEMKeyFile: SERVER_CERT,
- sslCAFile: CA_CERT
-};
-
-const mockKey = {
- keyName: "my_key",
- keyVaultEndpoint: "https://localhost:80",
-};
-
-const randomAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Random";
-
-const conn = MongoRunner.runMongod(x509_options);
-const test = conn.getDB("test");
-const collection = test.coll;
-
-function runKMS(mock_kms, func) {
- mock_kms.start();
-
- const azureKMS = {
- tenantId: "my_tentant",
- clientId: "access@mongodb.com",
- clientSecret: "secret",
- identityPlatformEndpoint: mock_kms.getURL(),
- };
-
- const clientSideFLEOptions = {
- kmsProviders: {
- azure: azureKMS,
- },
- keyVaultNamespace: "test.coll",
- schemaMap: {},
- };
-
- const shell = Mongo(conn.host, clientSideFLEOptions);
- const cleanCacheShell = Mongo(conn.host, clientSideFLEOptions);
-
- collection.drop();
-
- func(shell, cleanCacheShell);
-
- mock_kms.stop();
-}
-
-// OAuth faults must be tested first so a cached token cannot be used
-function testBadOAuthRequestResult() {
- const mock_kms = new MockKMSServerAzure(FAULT_OAUTH, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
-
- const error = assert.throws(() => keyVault.createKey("azure", mockKey, ["mongoKey"]));
- assert.eq(
- error,
- "Error: code 9: FailedToParse: Expecting '{': offset:0 of:Internal Error of some sort.");
- });
-}
-
-testBadOAuthRequestResult();
-
-function testBadOAuthRequestError() {
- const mock_kms = new MockKMSServerAzure(FAULT_OAUTH_CORRECT_FORMAT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
-
- const error = assert.throws(() => keyVault.createKey("azure", mockKey, ["mongoKey"]));
- assert.commandFailedWithCode(error, [ErrorCodes.OperationFailed]);
- assert.eq(
- error,
- "Error: Failed to make oauth request: Azure OAuth Error : FAULT_OAUTH_CORRECT_FORMAT");
- });
-}
-
-testBadOAuthRequestError();
-
-function testBadEncryptResult() {
- const mock_kms = new MockKMSServerAzure(FAULT_ENCRYPT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
- mockKey.keyVaultEndpoint = mock_kms.getEndpoint();
-
- assert.throws(() => keyVault.createKey("azure", mockKey, ["mongoKey"]));
- assert.eq(keyVault.getKeys("mongoKey").toArray().length, 0);
- });
-}
-
-testBadEncryptResult();
-
-function testBadEncryptError() {
- const mock_kms = new MockKMSServerAzure(FAULT_ENCRYPT_CORRECT_FORMAT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
- mockKey.keyVaultEndpoint = mock_kms.getEndpoint();
-
- let error = assert.throws(() => keyVault.createKey("azure", mockKey, ["mongoKey"]));
- assert.commandFailedWithCode(error, [5265103]);
- });
-}
-
-testBadEncryptError();
-
-function testBadDecryptResult() {
- const mock_kms = new MockKMSServerAzure(FAULT_DECRYPT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
- mockKey.keyVaultEndpoint = mock_kms.getEndpoint();
-
- const keyId = keyVault.createKey("azure", mockKey, ["mongoKey"]);
- const str = "mongo";
- assert.throws(() => {
- const encStr = shell.getClientEncryption().encrypt(keyId, str, randomAlgorithm);
- });
- });
-}
-
-testBadDecryptResult();
-
-function testBadDecryptKeyResult() {
- const mock_kms = new MockKMSServerAzure(FAULT_DECRYPT_WRONG_KEY, true);
-
- runKMS(mock_kms, (shell, cleanCacheShell) => {
- const keyVault = shell.getKeyVault();
- mockKey.keyVaultEndpoint = mock_kms.getEndpoint();
-
- keyVault.createKey("azure", mockKey, ["mongoKey"]);
- const keyId = keyVault.getKeys("mongoKey").toArray()[0]._id;
- const str = "mongo";
- const encStr = shell.getClientEncryption().encrypt(keyId, str, randomAlgorithm);
-
- mock_kms.enableFaults();
-
- assert.throws(() => {
- let str = cleanCacheShell.decrypt(encStr);
- });
- });
-}
-
-testBadDecryptKeyResult();
-
-function testBadDecryptError() {
- const mock_kms = new MockKMSServerAzure(FAULT_DECRYPT_CORRECT_FORMAT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
- mockKey.keyVaultEndpoint = mock_kms.getEndpoint();
-
- keyVault.createKey("azure", mockKey, ["mongoKey"]);
- const keyId = keyVault.getKeys("mongoKey").toArray()[0]._id;
- const str = "mongo";
- let error = assert.throws(() => {
- const encStr = shell.getClientEncryption().encrypt(keyId, str, randomAlgorithm);
- });
- assert.commandFailedWithCode(error, [5265103]);
- });
-}
-
-testBadDecryptError();
-
-MongoRunner.stopMongod(conn);
-})();
diff --git a/jstests/client_encrypt/fle_encrypt_decrypt_shell.js b/jstests/client_encrypt/fle_encrypt_decrypt_shell.js
index e586a25320b..27b6e3e5a51 100644
--- a/jstests/client_encrypt/fle_encrypt_decrypt_shell.js
+++ b/jstests/client_encrypt/fle_encrypt_decrypt_shell.js
@@ -1,15 +1,11 @@
/**
* Check the functionality of encrypt and decrypt functions in KeyStore.js
*/
-load("jstests/client_encrypt/lib/mock_kms.js");
load('jstests/ssl/libs/ssl_helpers.js');
(function() {
"use strict";
-const mock_kms = new MockKMSServerAWS();
-mock_kms.start();
-
const x509_options = {
sslMode: "requireSSL",
sslPEMKeyFile: SERVER_CERT,
@@ -20,12 +16,6 @@ const conn = MongoRunner.runMongod(x509_options);
const test = conn.getDB("test");
const collection = test.coll;
-const awsKMS = {
- accessKeyId: "access",
- secretAccessKey: "secret",
- url: mock_kms.getURL(),
-};
-
let localKMS = {
key: BinData(
0,
@@ -34,14 +24,13 @@ let localKMS = {
const clientSideFLEOptions = {
kmsProviders: {
- aws: awsKMS,
local: localKMS,
},
keyVaultNamespace: "test.coll",
schemaMap: {}
};
-const kmsTypes = ["aws", "local"];
+const kmsTypes = ["local"];
const randomAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Random";
const deterministicAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic";
@@ -124,5 +113,4 @@ for (const kmsType of kmsTypes) {
}
MongoRunner.stopMongod(conn);
-mock_kms.stop();
}());
diff --git a/jstests/client_encrypt/fle_gcp_faults.js b/jstests/client_encrypt/fle_gcp_faults.js
deleted file mode 100644
index 9bff963dfeb..00000000000
--- a/jstests/client_encrypt/fle_gcp_faults.js
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- * Verify the GCP KMS implementation can handle a buggy KMS.
- */
-
-load("jstests/client_encrypt/lib/mock_kms.js");
-load('jstests/ssl/libs/ssl_helpers.js');
-
-(function() {
-"use strict";
-
-const x509_options = {
- sslMode: "requireSSL",
- sslPEMKeyFile: SERVER_CERT,
- sslCAFile: CA_CERT
-};
-
-const mockKey = {
- projectId: "mock",
- location: "global",
- keyRing: "mock-key-ring",
- keyName: "mock-key"
-};
-
-const randomAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Random";
-
-const conn = MongoRunner.runMongod(x509_options);
-const test = conn.getDB("test");
-const collection = test.coll;
-
-function runKMS(mock_kms, func) {
- mock_kms.start();
-
- const gcpKMS = {
- email: "access@mongodb.com",
- endpoint: mock_kms.getURL(),
- // Arbitrary private key generated by openssl encoded in base64. A correctly formatted key
- // is required so the shell doesn't reject it, but the mock server doesn't actually use the
- // key to encrypt/decrypt.
- // The key is generated with `openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048`
- // which fulfills Windows's stricter requirements for RSA private keys
- privateKey:
- "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDDF3EoKeYp4GKgVckkSxe9Hr81TX/GHW+vSkwxZpI0LOia" +
- "rffIbv1IZ8xBD+HEL16E60pPZDYyNsmvNe6HRacSukTBM1peO5DrbM0VglEudoKc7TIT6trKFb1srd6WDUoGLZ6Xgm2KCmqZesV9VnWe" +
- "aLmbTa3TAZVn8nfDoRdLVl2ecE8BxrH63niMLQZl8qhcmeu61RQkOHbupTTovgH3PkufCOqgB01QHEcKgvPQBWqQvjms66U6Nfko2GMi" +
- "V5lPWWsJVBfNFU96M63QRxmjPWRoNNhui4xGPcm8u9GXo0p+83Ct2NZ7o3SxpaVUQaC2a2vbjADSI9G95fxM9z/zAgMBAAECggEBALOu" +
- "/pi4ZnXBZfU4rcaQpy+XhxKH65xD9l6jdqO1TgliJ2Z3vpTLrNqoR1bRUuYHnu2bbFjM+qGrFn0aljPe8i9sgfDT5HKQODytfAJIgY7i" +
- "tg/k40+26oZgGZRkW3MmkDw6fiwbg9o1F9N+YTC8lh4tZG3m0KdceQhBKQ90amkGaWsunC5/ZyI7Ip8JFFmkmoZHpiKJPYHI3dMNQyJK" +
- "cExSkw050UILIblPeA0AeDrtSBrz/5KfPKy0Wsh3cpuM9lE4dqupCnvp/GUZcSoG4NLg+I1FHQ/FkvY8AXtadES0JAty3E9GC60IWwvg" +
- "tdajFo4e1wlfyLgCFhAdsxslBokCgYEA7Emng/zBBF6IecuZWlekM286sUhLE2fSFRg+i5CjqsIJ0yAAIKAy5Qs8PV0TXtgLEg7M0nxG" +
- "9mnstkN5M2FSD4qEPe/teOJSzxgRavvqQCMtB9ABtz3nsXDQZbr5+/0bUxOsDbYW22t8dCavZ1u1SG+eC5PH/AGXLATBqR8Lfy8CgYEA" +
- "0134dkbZzy07z5cHDzTmsBZnhJt8W+Hix+5IViSnw3W+OdJFjMmUW8OmmBoMqzl69EaIU44bNpcLE1UOqNa74OGdNMid3p6JLUPSsiuh" +
- "9J1tH03+ZvubJQZiDiXDyXO7OeAX3ZQv0GAnK+LpYClcI50DwE655zzdbIn39iiuun0CgYEAn9XDBzl2p6n6z8i117LpVBGttjac8meM" +
- "aNCZnncc/2l6k+JVs7wqMV3ERg4sCEBEXNa+HrQKnK1Sfoht+B+hDvo4Ml2WWete8M/rGF+IOhKRZ3OBdZ7el90kW2x7pcW1MiFghXXj" +
- "SFIRQdDZXiVfH7zBQDubUBETXadqCSkC8ekCgYA6F22eNELQqgHyP/P0vflZFA9HZuR67E5D3L2Mz248TjQF+ECdPRnFTrSOwToSJS4h" +
- "zPDS5g+cpU6p9Yqd5MamO9vVEf4xnSjeg/F4fn14mXvQSsNM0oIFXwe8E60HxQMEGQ72GzA4+PRLH4Y8o6FrOFA7nmeBojzJA/JeeTfs" +
- "kQKBgQCh2Y1oIk7VcaP8F5vg1tw8VUuPadU3WqtDscenAli5Syp3ngDoIjtVII6mM8DxIE9tOrI+F653T/xcuVXjnPIymZh5LQttNABW" +
- "ZE1RXp16C1uFsg3F9U1wIljep+F6D/mjySkoaM8PwE1miLwThPGvgt2YSCyuig1OMOzOXlIUnQ==",
- };
-
- const clientSideFLEOptions = {
- kmsProviders: {
- gcp: gcpKMS,
- },
- keyVaultNamespace: "test.coll",
- schemaMap: {},
- };
-
- const shell = Mongo(conn.host, clientSideFLEOptions);
- const cleanCacheShell = Mongo(conn.host, clientSideFLEOptions);
-
- collection.drop();
-
- func(shell, cleanCacheShell);
-
- mock_kms.stop();
-}
-
-// OAuth faults must be tested first so a cached token can't be used
-function testBadOAuthRequestResult() {
- const mock_kms = new MockKMSServerGCP(FAULT_OAUTH, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
-
- const error = assert.throws(() => keyVault.createKey("gcp", mockKey, ["mongoKey"]));
- assert.eq(
- error,
- "Error: code 9: FailedToParse: Expecting '{': offset:0 of:Internal Error of some sort.");
- });
-}
-
-testBadOAuthRequestResult();
-
-function testBadOAuthRequestError() {
- const mock_kms = new MockKMSServerGCP(FAULT_OAUTH_CORRECT_FORMAT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
-
- const error = assert.throws(() => keyVault.createKey("gcp", mockKey, ["mongoKey"]));
- assert.commandFailedWithCode(error, [ErrorCodes.OperationFailed]);
- assert.eq(
- error,
- "Error: Failed to make oauth request: GCP OAuth Error : FAULT_OAUTH_CORRECT_FORMAT");
- });
-}
-
-testBadOAuthRequestError();
-
-function testBadEncryptResult() {
- const mock_kms = new MockKMSServerGCP(FAULT_ENCRYPT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
-
- assert.throws(() => keyVault.createKey("gcp", mockKey, ["mongoKey"]));
- assert.eq(keyVault.getKeys("mongoKey").toArray().length, 0);
- });
-}
-
-testBadEncryptResult();
-
-function testBadEncryptError() {
- const mock_kms = new MockKMSServerGCP(FAULT_ENCRYPT_CORRECT_FORMAT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
- let error = assert.throws(() => keyVault.createKey("gcp", mockKey, ["mongoKey"]));
- assert.commandFailedWithCode(error, [5256006]);
- });
-}
-
-testBadEncryptError();
-
-function testBadDecryptResult() {
- const mock_kms = new MockKMSServerGCP(FAULT_DECRYPT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
- const keyId = keyVault.createKey("gcp", mockKey, ["mongoKey"]);
- const str = "mongo";
- assert.throws(() => {
- const encStr = shell.getClientEncryption().encrypt(keyId, str, randomAlgorithm);
- });
- });
-}
-
-testBadDecryptResult();
-
-function testBadDecryptKeyResult() {
- const mock_kms = new MockKMSServerGCP(FAULT_DECRYPT_WRONG_KEY, true);
-
- runKMS(mock_kms, (shell, cleanCacheShell) => {
- const keyVault = shell.getKeyVault();
-
- keyVault.createKey("gcp", mockKey, ["mongoKey"]);
- const keyId = keyVault.getKeys("mongoKey").toArray()[0]._id;
- const str = "mongo";
- const encStr = shell.getClientEncryption().encrypt(keyId, str, randomAlgorithm);
-
- mock_kms.enableFaults();
-
- assert.throws(() => {
- let str = cleanCacheShell.decrypt(encStr);
- });
- });
-}
-
-testBadDecryptKeyResult();
-
-function testBadDecryptError() {
- const mock_kms = new MockKMSServerGCP(FAULT_DECRYPT_CORRECT_FORMAT, false);
-
- runKMS(mock_kms, (shell) => {
- const keyVault = shell.getKeyVault();
-
- keyVault.createKey("gcp", mockKey, ["mongoKey"]);
- const keyId = keyVault.getKeys("mongoKey").toArray()[0]._id;
- const str = "mongo";
- let error = assert.throws(() => {
- const encStr = shell.getClientEncryption().encrypt(keyId, str, randomAlgorithm);
- });
- assert.commandFailedWithCode(error, [5256008]);
- });
-}
-
-testBadDecryptError();
-
-MongoRunner.stopMongod(conn);
-})();
diff --git a/jstests/client_encrypt/fle_key_faults.js b/jstests/client_encrypt/fle_key_faults.js
index d58804460e6..204ee277ec5 100644
--- a/jstests/client_encrypt/fle_key_faults.js
+++ b/jstests/client_encrypt/fle_key_faults.js
@@ -2,15 +2,11 @@
* Verify the KMS support handles a buggy Key Store
*/
-load("jstests/client_encrypt/lib/mock_kms.js");
load('jstests/ssl/libs/ssl_helpers.js');
(function() {
"use strict";
-const mock_kms = new MockKMSServerAWS();
-mock_kms.start();
-
const x509_options = {
sslMode: "requireSSL",
sslPEMKeyFile: SERVER_CERT,
@@ -21,12 +17,6 @@ const conn = MongoRunner.runMongod(x509_options);
const test = conn.getDB("test");
const collection = test.coll;
-const awsKMS = {
- accessKeyId: "access",
- secretAccessKey: "secret",
- url: mock_kms.getURL(),
-};
-
var localKMS = {
key: BinData(
0,
@@ -35,7 +25,6 @@ var localKMS = {
const clientSideFLEOptions = {
kmsProviders: {
- aws: awsKMS,
local: localKMS,
},
keyVaultNamespace: "test.coll",
@@ -55,7 +44,7 @@ function testFault(kmsType, func) {
}
function testFaults(func) {
- const kmsTypes = ["aws", "local"];
+ const kmsTypes = ["local"];
for (const kmsType of kmsTypes) {
testFault(kmsType, func);
@@ -93,5 +82,4 @@ testFaults((keyId, shell) => {
});
MongoRunner.stopMongod(conn);
-mock_kms.stop();
}()); \ No newline at end of file
diff --git a/jstests/client_encrypt/fle_keys.js b/jstests/client_encrypt/fle_keys.js
index cbe32b6b586..93fb0000478 100644
--- a/jstests/client_encrypt/fle_keys.js
+++ b/jstests/client_encrypt/fle_keys.js
@@ -2,15 +2,11 @@
* Check functionality of KeyVault.js
*/
-load("jstests/client_encrypt/lib/mock_kms.js");
load('jstests/ssl/libs/ssl_helpers.js');
(function() {
"use strict";
-const mock_kms = new MockKMSServerAWS();
-mock_kms.start();
-
const x509_options = {
sslMode: "requireSSL",
sslPEMKeyFile: SERVER_CERT,
@@ -21,15 +17,15 @@ const conn = MongoRunner.runMongod(x509_options);
const test = conn.getDB("test");
const collection = test.coll;
-const awsKMS = {
- accessKeyId: "access",
- secretAccessKey: "secret",
- url: mock_kms.getURL(),
+const localKMS = {
+ key: BinData(
+ 0,
+ "tu9jUCBqZdwCelwE/EAm/4WqdxrSMi04B8e9uAV+m30rI1J2nhKZZtQjdvsSCwuI4erR6IEcEK+5eGUAODv43NDNIR9QheT2edWFewUfHKsl9cnzTc86meIzOmYl6drp"),
};
const clientSideFLEOptions = {
kmsProviders: {
- aws: awsKMS,
+ local: localKMS,
},
keyVaultNamespace: "test.coll",
schemaMap: {}
@@ -39,13 +35,13 @@ const conn_str = "mongodb://" + conn.host + "/?ssl=true";
const shell = Mongo(conn_str, clientSideFLEOptions);
const keyVault = shell.getKeyVault();
-keyVault.createKey("aws", "arn:aws:kms:us-east-1:fake:fake:fake", ['mongoKey']);
+keyVault.createKey("local", ['mongoKey']);
assert.eq(1, keyVault.getKeys().itcount());
-var result = keyVault.createKey("aws", "arn:aws:kms:us-east-4:fake:fake:fake", {});
+var result = keyVault.createKey("local", "fake", {});
assert.eq("TypeError: key alternate names must be of Array type.", result);
-result = keyVault.createKey("aws", "arn:aws:kms:us-east-5:fake:fake:fake", [1]);
+result = keyVault.createKey("local", [1]);
assert.eq("TypeError: items in key alternate names must be of String type.", result);
assert.eq(1, keyVault.getKeyByAltName("mongoKey").itcount());
@@ -72,12 +68,11 @@ result = keyVault.deleteKey(keyId);
assert.eq(0, keyVault.getKey(keyId).itcount());
assert.eq(0, keyVault.getKeys().itcount());
-keyVault.createKey("aws", "arn:aws:kms:us-east-1:fake:fake:fake1");
-keyVault.createKey("aws", "arn:aws:kms:us-east-2:fake:fake:fake2");
-keyVault.createKey("aws", "arn:aws:kms:us-east-3:fake:fake:fake3");
+keyVault.createKey("local", ['mongoKey1']);
+keyVault.createKey("local", ['mongoKey2']);
+keyVault.createKey("local", ['mongoKey3']);
assert.eq(3, keyVault.getKeys().itcount());
MongoRunner.stopMongod(conn);
-mock_kms.stop();
}()); \ No newline at end of file
diff --git a/jstests/client_encrypt/fle_valid_fle_options.js b/jstests/client_encrypt/fle_valid_fle_options.js
index e95eb89795f..74e77443ec2 100644
--- a/jstests/client_encrypt/fle_valid_fle_options.js
+++ b/jstests/client_encrypt/fle_valid_fle_options.js
@@ -1,13 +1,9 @@
-load("jstests/client_encrypt/lib/mock_kms.js");
load('jstests/ssl/libs/ssl_helpers.js');
(function() {
"use strict";
-const mock_kms = new MockKMSServerAWS();
-mock_kms.start();
-
const randomAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Random";
const deterministicAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic";
@@ -22,16 +18,16 @@ const conn = MongoRunner.runMongod(x509_options);
const unencryptedDatabase = conn.getDB("test");
const collection = unencryptedDatabase.keystore;
-const awsKMS = {
- accessKeyId: "access",
- secretAccessKey: "secret",
- url: mock_kms.getURL(),
+const localKMS = {
+ key: BinData(
+ 0,
+ "tu9jUCBqZdwCelwE/EAm/4WqdxrSMi04B8e9uAV+m30rI1J2nhKZZtQjdvsSCwuI4erR6IEcEK+5eGUAODv43NDNIR9QheT2edWFewUfHKsl9cnzTc86meIzOmYl6drp"),
};
const clientSideFLEOptionsFail = [
{
kmsProviders: {
- aws: awsKMS,
+ local: localKMS,
},
schemaMap: {},
},
@@ -48,7 +44,7 @@ clientSideFLEOptionsFail.forEach(element => {
const clientSideFLEOptionsPass = [
{
kmsProviders: {
- aws: awsKMS,
+ local: localKMS,
},
keyVaultNamespace: "test.keystore",
schemaMap: {},
@@ -62,5 +58,4 @@ clientSideFLEOptionsPass.forEach(element => {
});
MongoRunner.stopMongod(conn);
-mock_kms.stop();
}());
diff --git a/jstests/client_encrypt/lib/fle_command_line_explicit_encryption.js b/jstests/client_encrypt/lib/fle_command_line_explicit_encryption.js
index 1e89f348917..3cef4036e5f 100644
--- a/jstests/client_encrypt/lib/fle_command_line_explicit_encryption.js
+++ b/jstests/client_encrypt/lib/fle_command_line_explicit_encryption.js
@@ -3,14 +3,9 @@
* jstests/fle/fle_command_line_encryption.js.
*/
-load("jstests/client_encrypt/lib/mock_kms.js");
-
(function() {
"use strict";
-const mock_kms = new MockKMSServerAWS();
-mock_kms.start();
-
const shell = Mongo();
const keyVault = shell.getKeyVault();
@@ -51,7 +46,7 @@ const failTestCases = [null, undefined, MinKey(), MaxKey(), DBRef("test", "test"
for (const encryptionAlgorithm of encryptionAlgorithms) {
collection.drop();
- keyVault.createKey("aws", "arn:aws:kms:us-east-1:fake:fake:fake", ['mongoKey']);
+ keyVault.createKey("local", ['mongoKey']);
const keyId = keyVault.getKeyByAltName("mongoKey").toArray()[0]._id;
let pass;
@@ -78,6 +73,5 @@ for (const encryptionAlgorithm of encryptionAlgorithms) {
}
}
-mock_kms.stop();
print("Test completed with no errors.");
}());
diff --git a/jstests/client_encrypt/lib/kms_http_common.py b/jstests/client_encrypt/lib/kms_http_common.py
deleted file mode 100644
index 2ee0828d9cf..00000000000
--- a/jstests/client_encrypt/lib/kms_http_common.py
+++ /dev/null
@@ -1,148 +0,0 @@
-"""Common code for mock kms http endpoint."""
-import http.server
-import json
-import ssl
-import urllib.parse
-from abc import abstractmethod
-
-URL_PATH_STATS = "/stats"
-URL_DISABLE_FAULTS = "/disable_faults"
-URL_ENABLE_FAULTS = "/enable_faults"
-
-"""Fault which causes encrypt to return 500."""
-FAULT_ENCRYPT = "fault_encrypt"
-
-"""Fault which causes encrypt to return an error that contains a type and message"""
-FAULT_ENCRYPT_CORRECT_FORMAT = "fault_encrypt_correct_format"
-
-"""Fault which causes encrypt to return wrong fields in JSON."""
-FAULT_ENCRYPT_WRONG_FIELDS = "fault_encrypt_wrong_fields"
-
-"""Fault which causes encrypt to return bad BASE64."""
-FAULT_ENCRYPT_BAD_BASE64 = "fault_encrypt_bad_base64"
-
-"""Fault which causes decrypt to return 500."""
-FAULT_DECRYPT = "fault_decrypt"
-
-"""Fault which causes decrypt to return an error that contains a type and message"""
-FAULT_DECRYPT_CORRECT_FORMAT = "fault_decrypt_correct_format"
-
-"""Fault which causes decrypt to return wrong key."""
-FAULT_DECRYPT_WRONG_KEY = "fault_decrypt_wrong_key"
-
-"""Fault which causes an OAuth request to return an 500."""
-FAULT_OAUTH = "fault_oauth"
-
-"""Fault which causes an OAuth request to return an error response"""
-FAULT_OAUTH_CORRECT_FORMAT = "fault_oauth_correct_format"
-
-
-class Stats:
- """Stats class shared between client and server."""
-
- def __init__(self):
- self.encrypt_calls = 0
- self.decrypt_calls = 0
- self.fault_calls = 0
-
- def __repr__(self):
- return json.dumps({
- 'decrypts': self.decrypt_calls,
- 'encrypts': self.encrypt_calls,
- 'faults': self.fault_calls,
- })
-
-
-class KmsHandlerBase(http.server.BaseHTTPRequestHandler):
- protocol_version = "HTTP/1.1"
-
- def do_GET(self):
- """Serve a Test GET request."""
- print("Received GET: " + self.path)
- parts = urllib.parse.urlsplit(self.path)
- path = parts[2]
-
- if path == URL_PATH_STATS:
- self._do_stats()
- elif path == URL_DISABLE_FAULTS:
- self._do_disable_faults()
- elif path == URL_ENABLE_FAULTS:
- self._do_enable_faults()
- else:
- self.send_response(http.HTTPStatus.NOT_FOUND)
- self.end_headers()
- self.wfile.write("Unknown URL".encode())
-
- @abstractmethod
- def do_POST(self):
- """Serve a POST request."""
- pass
-
- def _send_reply(self, data, status=http.HTTPStatus.OK):
- print("Sending Response: " + data.decode())
-
- self.send_response(status)
- self.send_header("content-type", "application/octet-stream")
- self.send_header("Content-Length", str(len(data)))
- self.end_headers()
-
- self.wfile.write(data)
-
- @abstractmethod
- def _do_encrypt(self, raw_input):
- pass
-
- @abstractmethod
- def _do_encrypt_faults(self, raw_ciphertext):
- pass
-
- @abstractmethod
- def _do_decrypt(self, raw_input):
- pass
-
- @abstractmethod
- def _do_decrypt_faults(self, blob):
- pass
-
- def _send_header(self):
- self.send_response(http.HTTPStatus.OK)
- self.send_header("content-type", "application/octet-stream")
- self.end_headers()
-
- def _do_stats(self):
- self._send_header()
-
- self.wfile.write(str(stats).encode('utf-8'))
-
- def _do_disable_faults(self):
- global disable_faults
- disable_faults = True
- self._send_header()
-
- def _do_enable_faults(self):
- global disable_faults
- disable_faults = False
- self._send_header()
-
-
-def run(port, cert_file, ca_file, handler_class, server_class=http.server.HTTPServer):
- """Run web server."""
- server_address = ('', port)
-
- httpd = server_class(server_address, handler_class)
-
- httpd.socket = ssl.wrap_socket(httpd.socket,
- certfile=cert_file,
- ca_certs=ca_file, server_side=True)
-
- print(f"Mock KMS Web Server Listening on {str(server_address)}")
-
- httpd.serve_forever()
-
-
-# Pass this data out of band instead of storing it in AwsKmsHandler since the
-# BaseHTTPRequestHandler does not call the methods as object methods but as class methods. This
-# means there is not self.
-stats = Stats()
-disable_faults = False
-fault_type = None
diff --git a/jstests/client_encrypt/lib/kms_http_control.py b/jstests/client_encrypt/lib/kms_http_control.py
deleted file mode 100644
index c290ae80a25..00000000000
--- a/jstests/client_encrypt/lib/kms_http_control.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#! /usr/bin/env python3
-"""
-Python script to interact with mock AWS KMS HTTP server.
-"""
-
-import argparse
-import json
-import logging
-import sys
-import urllib.request
-import ssl
-
-import kms_http_common
-
-def main():
- """Main entry point."""
- parser = argparse.ArgumentParser(description='MongoDB Mock KMS Endpoint.')
-
- parser.add_argument('-p', '--port', type=int, default=8000, help="Port to listen on")
-
- parser.add_argument('-v', '--verbose', action='count', help="Enable verbose tracing")
-
- parser.add_argument('--ca_file', type=str, required=True, help="TLS CA PEM file")
-
- parser.add_argument('--query', type=str, help="Query endpoint <name>")
-
- args = parser.parse_args()
- if args.verbose:
- logging.basicConfig(level=logging.DEBUG)
-
- url_str = "https://localhost:" + str(args.port)
- if args.query == "stats":
- url_str += kms_http_common.URL_PATH_STATS
- elif args.query == "disable_faults":
- url_str += kms_http_common.URL_DISABLE_FAULTS
- elif args.query == "enable_faults":
- url_str += kms_http_common.URL_ENABLE_FAULTS
- else:
- print("Unknown query type")
- sys.exit(1)
-
- context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=args.ca_file)
-
- with urllib.request.urlopen(url_str, context=context) as f:
- print(f.read().decode('utf-8'))
-
- sys.exit(0)
-
-
-if __name__ == '__main__':
-
- main()
diff --git a/jstests/client_encrypt/lib/kms_http_server.py b/jstests/client_encrypt/lib/kms_http_server.py
deleted file mode 100755
index 489b6230424..00000000000
--- a/jstests/client_encrypt/lib/kms_http_server.py
+++ /dev/null
@@ -1,244 +0,0 @@
-#! /usr/bin/env python3
-"""Mock AWS KMS Endpoint."""
-
-import argparse
-import base64
-import http.server
-import json
-import logging
-import sys
-import urllib.parse
-
-from botocore.auth import SigV4Auth
-from botocore.awsrequest import AWSRequest
-from botocore.credentials import Credentials
-
-import kms_http_common
-
-SECRET_PREFIX = "00SECRET"
-
-# List of supported fault types
-SUPPORTED_FAULT_TYPES = [
- kms_http_common.FAULT_ENCRYPT,
- kms_http_common.FAULT_ENCRYPT_CORRECT_FORMAT,
- kms_http_common.FAULT_ENCRYPT_WRONG_FIELDS,
- kms_http_common.FAULT_ENCRYPT_BAD_BASE64,
- kms_http_common.FAULT_DECRYPT,
- kms_http_common.FAULT_DECRYPT_CORRECT_FORMAT,
- kms_http_common.FAULT_DECRYPT_WRONG_KEY,
-]
-
-def get_dict_subset(headers, subset):
- ret = {}
- for header in headers.keys():
- if header.lower() in subset.lower():
- ret[header] = headers[header]
- return ret
-
-class AwsKmsHandler(kms_http_common.KmsHandlerBase):
- """
- Handle requests from AWS KMS Monitoring and test commands
- """
-
- def do_POST(self):
- print("Received POST: " + self.path)
- parts = urllib.parse.urlsplit(self.path)
- path = parts[2]
-
- if path == "/":
- self._do_post()
- else:
- self.send_response(http.HTTPStatus.NOT_FOUND)
- self.end_headers()
- self.wfile.write("Unknown URL".encode())
-
- def _do_post(self):
- clen = int(self.headers.get('content-length'))
-
- raw_input = self.rfile.read(clen)
-
- print("RAW INPUT: " + str(raw_input))
-
- if not self.headers["Host"] == "localhost":
- data = "Unexpected host"
- self._send_reply(data.encode("utf-8"))
-
- if not self._validate_signature(self.headers, raw_input):
- data = "Bad Signature"
- self._send_reply(data.encode("utf-8"))
-
- # X-Amz-Target: TrentService.Encrypt
- aws_operation = self.headers['X-Amz-Target']
-
- if aws_operation == "TrentService.Encrypt":
- kms_http_common.stats.encrypt_calls += 1
- self._do_encrypt(raw_input)
- elif aws_operation == "TrentService.Decrypt":
- kms_http_common.stats.decrypt_calls += 1
- self._do_decrypt(raw_input)
- else:
- data = "Unknown AWS Operation"
- self._send_reply(data.encode("utf-8"))
-
- def _validate_signature(self, headers, raw_input):
- auth_header = headers["Authorization"]
- signed_headers_start = auth_header.find("SignedHeaders")
- signed_headers = auth_header[signed_headers_start:auth_header.find(",", signed_headers_start)]
- signed_headers_dict = get_dict_subset(headers, signed_headers)
-
- request = AWSRequest(method="POST", url="/", data=raw_input, headers=signed_headers_dict)
- # SigV4Auth assumes this header exists even though it is not required by the algorithm
- request.context['timestamp'] = headers['X-Amz-Date']
-
- region_start = auth_header.find("Credential=access/") + len("Credential=access/YYYYMMDD/")
- region = auth_header[region_start:auth_header.find("/", region_start)]
-
- credentials = Credentials("access", "secret")
- auth = SigV4Auth(credentials, "kms", region)
- string_to_sign = auth.string_to_sign(request, auth.canonical_request(request))
- expected_signature = auth.signature(string_to_sign, request)
-
- signature_headers_start = auth_header.find("Signature=") + len("Signature=")
- actual_signature = auth_header[signature_headers_start:]
-
- return expected_signature == actual_signature
-
- def _do_encrypt(self, raw_input):
- request = json.loads(raw_input)
-
- print(request)
-
- plaintext = request["Plaintext"]
- keyid = request["KeyId"]
-
- ciphertext = SECRET_PREFIX.encode() + plaintext.encode()
- ciphertext = base64.b64encode(ciphertext).decode()
-
- if kms_http_common.fault_type and kms_http_common.fault_type.startswith(kms_http_common.FAULT_ENCRYPT) \
- and not kms_http_common.disable_faults:
- return self._do_encrypt_faults(ciphertext)
-
- response = {
- "CiphertextBlob" : ciphertext,
- "KeyId" : keyid,
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
-
- def _do_encrypt_faults(self, raw_ciphertext):
- kms_http_common.stats.fault_calls += 1
-
- if kms_http_common.fault_type == kms_http_common.FAULT_ENCRYPT:
- self._send_reply("Internal Error of some sort.".encode(), http.HTTPStatus.INTERNAL_SERVER_ERROR)
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_ENCRYPT_WRONG_FIELDS:
- response = {
- "SomeBlob" : raw_ciphertext,
- "KeyId" : "foo",
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_ENCRYPT_BAD_BASE64:
- response = {
- "CiphertextBlob" : "foo",
- "KeyId" : "foo",
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_ENCRYPT_CORRECT_FORMAT:
- response = {
- "__type" : "NotFoundException",
- "Message" : "Error encrypting message",
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
-
- raise ValueError("Unknown Fault Type: " + kms_http_common.fault_type)
-
- def _do_decrypt(self, raw_input):
- request = json.loads(raw_input)
- blob = base64.b64decode(request["CiphertextBlob"]).decode()
-
- print("FOUND SECRET: " + blob)
-
- # our "encrypted" values start with the word SECRET_PREFIX otherwise they did not come from us
- if not blob.startswith(SECRET_PREFIX):
- raise ValueError()
-
- blob = blob[len(SECRET_PREFIX):]
-
- if kms_http_common.fault_type and kms_http_common.fault_type.startswith(kms_http_common.FAULT_DECRYPT) \
- and not kms_http_common.disable_faults:
- return self._do_decrypt_faults(blob)
-
- response = {
- "Plaintext" : blob,
- "KeyId" : "Not a clue",
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
-
- def _do_decrypt_faults(self, blob):
- kms_http_common.stats.fault_calls += 1
-
- if kms_http_common.fault_type == kms_http_common.FAULT_DECRYPT:
- self._send_reply("Internal Error of some sort.".encode(), http.HTTPStatus.INTERNAL_SERVER_ERROR)
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_DECRYPT_WRONG_KEY:
- response = {
- "Plaintext" : "ta7DXE7J0OiCRw03dYMJSeb8nVF5qxTmZ9zWmjuX4zW/SOorSCaY8VMTWG+cRInMx/rr/+QeVw2WjU2IpOSvMg==",
- "KeyId" : "Not a clue",
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_DECRYPT_CORRECT_FORMAT:
- response = {
- "__type" : "NotFoundException",
- "Message" : "Error decrypting message",
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
-
- raise ValueError("Unknown Fault Type: " + kms_http_common.fault_type)
-
-def main():
- """Main Method."""
- parser = argparse.ArgumentParser(description='MongoDB Mock AWS KMS Endpoint.')
-
- parser.add_argument('-p', '--port', type=int, default=8000, help="Port to listen on")
-
- parser.add_argument('-v', '--verbose', action='count', help="Enable verbose tracing")
-
- parser.add_argument('--fault', type=str, help="Type of fault to inject")
-
- parser.add_argument('--disable-faults', action='store_true', help="Disable faults on startup")
-
- parser.add_argument('--ca_file', type=str, required=True, help="TLS CA PEM file")
-
- parser.add_argument('--cert_file', type=str, required=True, help="TLS Server PEM file")
-
- args = parser.parse_args()
- if args.verbose:
- logging.basicConfig(level=logging.DEBUG)
-
- if args.fault:
- if args.fault not in SUPPORTED_FAULT_TYPES:
- print("Unsupported fault type %s, supports types are %s" % (args.fault, SUPPORTED_FAULT_TYPES))
- sys.exit(1)
-
- kms_http_common.fault_type = args.fault
-
- if args.disable_faults:
- kms_http_common.disable_faults = True
-
- kms_http_common.run(args.port, args.cert_file, args.ca_file, AwsKmsHandler)
-
-
-if __name__ == '__main__':
-
- main()
diff --git a/jstests/client_encrypt/lib/kms_http_server_azure.py b/jstests/client_encrypt/lib/kms_http_server_azure.py
deleted file mode 100755
index af2b7b4a016..00000000000
--- a/jstests/client_encrypt/lib/kms_http_server_azure.py
+++ /dev/null
@@ -1,239 +0,0 @@
-#! /usr/bin/env python3
-"""Mock Azure KMS Endpoint."""
-import argparse
-import base64
-import http
-import json
-import logging
-import urllib.parse
-import sys
-
-import kms_http_common
-
-SUPPORTED_FAULT_TYPES = [
- kms_http_common.FAULT_ENCRYPT,
- kms_http_common.FAULT_ENCRYPT_CORRECT_FORMAT,
- kms_http_common.FAULT_DECRYPT,
- kms_http_common.FAULT_DECRYPT_CORRECT_FORMAT,
- kms_http_common.FAULT_DECRYPT_WRONG_KEY,
- kms_http_common.FAULT_OAUTH,
- kms_http_common.FAULT_OAUTH_CORRECT_FORMAT,
-]
-
-SECRET_PREFIX = "00SECRET"
-FAKE_OAUTH_TOKEN = "omg_im_an_oauth_token"
-
-URL_PATH_OAUTH_AUDIENCE = "/token"
-URL_PATH_OAUTH_SCOPE = "/auth/cloudkms"
-URL_PATH_MOCK_KEY = "/keys/my_key/"
-
-
-class AzureKmsHandler(kms_http_common.KmsHandlerBase):
- """
- Handle requests from Azure KMS Monitoring and test commands
- """
-
- def do_POST(self):
- """Serve a POST request."""
- print("Received POST: " + self.path)
- parts = urllib.parse.urlsplit(self.path)
- path = parts[2]
-
- if path == "/my_tentant/oauth2/v2.0/token":
- self._do_oauth_request()
- elif path.startswith(URL_PATH_MOCK_KEY):
- self._do_operation()
- else:
- self.send_response(http.HTTPStatus.NOT_FOUND)
- self.end_headers()
- self.wfile.write("Unknown URL".encode())
-
- def _do_operation(self):
- clen = int(self.headers.get("content-length"))
-
- raw_input = self.rfile.read(clen)
-
- print(f"RAW INPUT: {str(raw_input)}")
-
- if not self.headers["Host"] == "localhost":
- data = "Unexpected host"
- self._send_reply(data.encode("utf-8"))
-
- if not self.headers["Authorization"] == f"Bearer {FAKE_OAUTH_TOKEN}":
- data = "Unexpected bearer token"
- self._send_reply(data.encode("utf-8"))
-
- parts = urllib.parse.urlsplit(self.path)
- operation = parts.path.split('/')[-1]
-
- if operation == "wrapkey":
- self._do_encrypt(raw_input)
- elif operation == "unwrapkey":
- self._do_decrypt(raw_input)
- else:
- self._send_reply(f"Unknown operation: {operation}".encode("utf-8"))
-
- def _do_encrypt(self, raw_input):
- request = json.loads(raw_input)
-
- print(request)
-
- plaintext = request["value"]
-
- ciphertext = SECRET_PREFIX.encode() + plaintext.encode()
- ciphertext = base64.urlsafe_b64encode(ciphertext).decode()
-
- if kms_http_common.fault_type and kms_http_common.fault_type.startswith(kms_http_common.FAULT_ENCRYPT) \
- and not kms_http_common.disable_faults:
- return self._do_encrypt_faults(ciphertext)
-
- response = {
- "value": ciphertext,
- "kid": "my_key",
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
-
- def _do_encrypt_faults(self, raw_ciphertext):
- kms_http_common.stats.fault_calls += 1
-
- if kms_http_common.fault_type == kms_http_common.FAULT_ENCRYPT:
- self._send_reply("Internal Error of some sort.".encode(), http.HTTPStatus.INTERNAL_SERVER_ERROR)
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_ENCRYPT_CORRECT_FORMAT:
- response = {
- "error": {
- "code": "bad",
- "message": "Error encrypting message",
- }
- }
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
-
- raise ValueError("Unknown Fault Type: " + kms_http_common.fault_type)
-
- def _do_decrypt(self, raw_input):
- request = json.loads(raw_input)
- blob = base64.urlsafe_b64decode(request["value"]).decode()
-
- print("FOUND SECRET: " + blob)
-
- # our "encrypted" values start with the word SECRET_PREFIX otherwise they did not come from us
- if not blob.startswith(SECRET_PREFIX):
- raise ValueError()
-
- blob = blob[len(SECRET_PREFIX):]
-
- if kms_http_common.fault_type and kms_http_common.fault_type.startswith(kms_http_common.FAULT_DECRYPT) \
- and not kms_http_common.disable_faults:
- return self._do_decrypt_faults(blob)
-
- response = {
- "kid": "my_key",
- "value": blob,
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
-
- def _do_decrypt_faults(self, blob):
- kms_http_common.stats.fault_calls += 1
-
- if kms_http_common.fault_type == kms_http_common.FAULT_DECRYPT:
- self._send_reply("Internal Error of some sort.".encode(), http.HTTPStatus.INTERNAL_SERVER_ERROR)
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_DECRYPT_WRONG_KEY:
- response = {
- "kid": "my_key",
- "value": "ta7DXE7J0OiCRw03dYMJSeb8nVF5qxTmZ9zWmjuX4zW/SOorSCaY8VMTWG+cRInMx/rr/+QeVw2WjU2IpOSvMg==",
- }
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_DECRYPT_CORRECT_FORMAT:
- response = {
- "error": {
- "code": "bad",
- "message": "Error decrypting message",
- }
- }
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
-
- raise ValueError("Unknown Fault Type: " + kms_http_common.fault_type)
-
- def _do_oauth_request(self):
- clen = int(self.headers.get('content-length'))
-
- raw_input = self.rfile.read(clen)
-
- print(f"RAW INPUT: {str(raw_input)}")
-
- if not self.headers["Host"] == "localhost":
- data = "Unexpected host"
- self._send_reply(data.encode("utf-8"))
-
- if kms_http_common.fault_type and kms_http_common.fault_type.startswith(kms_http_common.FAULT_OAUTH) \
- and not kms_http_common.disable_faults:
- return self._do_oauth_faults()
-
- response = {
- "access_token": FAKE_OAUTH_TOKEN,
- "scope": self.headers["Host"] + URL_PATH_OAUTH_SCOPE,
- "token_type": "Bearer",
- "expires_in": 3600,
- }
-
- self._send_reply(json.dumps(response).encode("utf-8"))
-
- def _do_oauth_faults(self):
- kms_http_common.stats.fault_calls += 1
-
- if kms_http_common.fault_type == kms_http_common.FAULT_OAUTH:
- self._send_reply("Internal Error of some sort.".encode(), http.HTTPStatus.INTERNAL_SERVER_ERROR)
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_OAUTH_CORRECT_FORMAT:
- response = {
- "error": "Azure OAuth Error",
- "error_description": "FAULT_OAUTH_CORRECT_FORMAT",
- "error_uri": "https://mongodb.com/whoopsies.pdf",
- }
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
-
- raise ValueError("Unknown Fault Type: " + kms_http_common.fault_type)
-
-
-def main():
- """Main Method."""
- parser = argparse.ArgumentParser(description='MongoDB Mock Azure KMS Endpoint.')
-
- parser.add_argument('-p', '--port', type=int, default=8000, help="Port to listen on")
-
- parser.add_argument('-v', '--verbose', action='count', help="Enable verbose tracing")
-
- parser.add_argument('--fault', type=str, help="Type of fault to inject")
-
- parser.add_argument('--disable-faults', action='store_true', help="Disable faults on startup")
-
- parser.add_argument('--ca_file', type=str, required=True, help="TLS CA PEM file")
-
- parser.add_argument('--cert_file', type=str, required=True, help="TLS Server PEM file")
-
- args = parser.parse_args()
- if args.verbose:
- logging.basicConfig(level=logging.DEBUG)
-
- if args.fault:
- if args.fault not in SUPPORTED_FAULT_TYPES:
- print("Unsupported fault type %s, supports types are %s" % (args.fault, SUPPORTED_FAULT_TYPES))
- sys.exit(1)
-
- kms_http_common.fault_type = args.fault
-
- if args.disable_faults:
- kms_http_common.disable_faults = True
-
- kms_http_common.run(args.port, args.cert_file, args.ca_file, AzureKmsHandler)
-
-
-if __name__ == '__main__':
- main()
diff --git a/jstests/client_encrypt/lib/kms_http_server_gcp.py b/jstests/client_encrypt/lib/kms_http_server_gcp.py
deleted file mode 100755
index 8ce42081e01..00000000000
--- a/jstests/client_encrypt/lib/kms_http_server_gcp.py
+++ /dev/null
@@ -1,240 +0,0 @@
-#! /usr/bin/env python3
-"""Mock GCP KMS Endpoint."""
-import argparse
-import base64
-import http
-import json
-import logging
-import urllib.parse
-import sys
-
-import kms_http_common
-
-SUPPORTED_FAULT_TYPES = [
- kms_http_common.FAULT_ENCRYPT,
- kms_http_common.FAULT_ENCRYPT_CORRECT_FORMAT,
- kms_http_common.FAULT_DECRYPT,
- kms_http_common.FAULT_DECRYPT_CORRECT_FORMAT,
- kms_http_common.FAULT_DECRYPT_WRONG_KEY,
- kms_http_common.FAULT_OAUTH,
- kms_http_common.FAULT_OAUTH_CORRECT_FORMAT,
-]
-
-SECRET_PREFIX = "00SECRET"
-FAKE_OAUTH_TOKEN = "omg_im_an_oauth_token"
-
-URL_PATH_OAUTH_AUDIENCE = "/token"
-URL_PATH_OAUTH_SCOPE = "/auth/cloudkms"
-URL_PATH_MOCK_KEY = "/v1/projects/mock/locations/global/keyRings/mock-key-ring/cryptoKeys/mock-key"
-
-
-class GcpKmsHandler(kms_http_common.KmsHandlerBase):
- """
- Handle requests from GCP KMS Monitoring and test commands
- """
-
- def do_POST(self):
- """Serve a POST request."""
- print("Received POST: " + self.path)
- parts = urllib.parse.urlsplit(self.path)
- path = parts[2]
-
- if path == "/token":
- self._do_oauth_request()
- elif path.startswith(URL_PATH_MOCK_KEY):
- self._do_operation()
- else:
- self.send_response(http.HTTPStatus.NOT_FOUND)
- self.end_headers()
- self.wfile.write("Unknown URL".encode())
-
- def _do_operation(self):
- clen = int(self.headers.get("content-length"))
-
- raw_input = self.rfile.read(clen)
-
- print(f"RAW INPUT: {str(raw_input)}")
-
- if not self.headers["Host"] == "localhost":
- data = "Unexpected host"
- self._send_reply(data.encode("utf-8"))
-
- if not self.headers["Authorization"] == f"Bearer {FAKE_OAUTH_TOKEN}":
- data = "Unexpected bearer token"
- self._send_reply(data.encode("utf-8"))
-
- parts = urllib.parse.urlsplit(self.path)
- path = parts[2]
- operation = path.split(":")[1]
-
- if operation == "encrypt":
- self._do_encrypt(raw_input)
- elif operation == "decrypt":
- self._do_decrypt(raw_input)
- else:
- self._send_reply(f"Unknown operation: {operation}".encode("utf-8"))
-
- def _do_encrypt(self, raw_input):
- request = json.loads(raw_input)
-
- print(request)
-
- plaintext = request["plaintext"]
-
- ciphertext = SECRET_PREFIX.encode() + plaintext.encode()
- ciphertext = base64.b64encode(ciphertext).decode()
-
- if kms_http_common.fault_type and kms_http_common.fault_type.startswith(kms_http_common.FAULT_ENCRYPT) \
- and not kms_http_common.disable_faults:
- return self._do_encrypt_faults(ciphertext)
-
- response = {
- "ciphertext": ciphertext,
- "name": "mockEncryptResponse",
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
-
- def _do_encrypt_faults(self, raw_ciphertext):
- kms_http_common.stats.fault_calls += 1
-
- if kms_http_common.fault_type == kms_http_common.FAULT_ENCRYPT:
- self._send_reply("Internal Error of some sort.".encode(), http.HTTPStatus.INTERNAL_SERVER_ERROR)
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_ENCRYPT_CORRECT_FORMAT:
- response = {
- "error": {
- "code": 1337,
- "message": "Error encrypting message",
- "status": "Dummy Status",
- }
- }
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
-
- raise ValueError("Unknown Fault Type: " + kms_http_common.fault_type)
-
- def _do_decrypt(self, raw_input):
- request = json.loads(raw_input)
- blob = base64.b64decode(request["ciphertext"]).decode()
-
- print("FOUND SECRET: " + blob)
-
- # our "encrypted" values start with the word SECRET_PREFIX otherwise they did not come from us
- if not blob.startswith(SECRET_PREFIX):
- raise ValueError()
-
- blob = blob[len(SECRET_PREFIX):]
-
- if kms_http_common.fault_type and kms_http_common.fault_type.startswith(kms_http_common.FAULT_DECRYPT) \
- and not kms_http_common.disable_faults:
- return self._do_decrypt_faults(blob)
-
- response = {
- "plaintext": blob,
- }
-
- self._send_reply(json.dumps(response).encode('utf-8'))
-
- def _do_decrypt_faults(self, blob):
- kms_http_common.stats.fault_calls += 1
-
- if kms_http_common.fault_type == kms_http_common.FAULT_DECRYPT:
- self._send_reply("Internal Error of some sort.".encode(), http.HTTPStatus.INTERNAL_SERVER_ERROR)
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_DECRYPT_WRONG_KEY:
- response = {
- "plaintext": "ta7DXE7J0OiCRw03dYMJSeb8nVF5qxTmZ9zWmjuX4zW/SOorSCaY8VMTWG+cRInMx/rr/+QeVw2WjU2IpOSvMg==",
- }
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_DECRYPT_CORRECT_FORMAT:
- response = {
- "error": {
- "code": 9001,
- "message": "Error decrypting message",
- "status": "Dummy Status",
- }
- }
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
-
- raise ValueError("Unknown Fault Type: " + kms_http_common.fault_type)
-
- def _do_oauth_request(self):
- clen = int(self.headers.get('content-length'))
-
- raw_input = self.rfile.read(clen)
-
- print(f"RAW INPUT: {str(raw_input)}")
-
- if not self.headers["Host"] == "localhost":
- data = "Unexpected host"
- self._send_reply(data.encode("utf-8"))
-
- if kms_http_common.fault_type and kms_http_common.fault_type.startswith(kms_http_common.FAULT_OAUTH) \
- and not kms_http_common.disable_faults:
- return self._do_oauth_faults()
-
- response = {
- "access_token": FAKE_OAUTH_TOKEN,
- "scope": self.headers["Host"] + URL_PATH_OAUTH_SCOPE,
- "token_type": "Bearer",
- "expires_in": 3600,
- }
-
- self._send_reply(json.dumps(response).encode("utf-8"))
-
- def _do_oauth_faults(self):
- kms_http_common.stats.fault_calls += 1
-
- if kms_http_common.fault_type == kms_http_common.FAULT_OAUTH:
- self._send_reply("Internal Error of some sort.".encode(), http.HTTPStatus.INTERNAL_SERVER_ERROR)
- return
- elif kms_http_common.fault_type == kms_http_common.FAULT_OAUTH_CORRECT_FORMAT:
- response = {
- "error": "GCP OAuth Error",
- "error_description": "FAULT_OAUTH_CORRECT_FORMAT",
- "error_uri": "https://mongodb.com/whoopsies.pdf",
- }
- self._send_reply(json.dumps(response).encode('utf-8'))
- return
-
- raise ValueError("Unknown Fault Type: " + kms_http_common.fault_type)
-
-
-def main():
- """Main Method."""
- parser = argparse.ArgumentParser(description='MongoDB Mock GCP KMS Endpoint.')
-
- parser.add_argument('-p', '--port', type=int, default=8000, help="Port to listen on")
-
- parser.add_argument('-v', '--verbose', action='count', help="Enable verbose tracing")
-
- parser.add_argument('--fault', type=str, help="Type of fault to inject")
-
- parser.add_argument('--disable-faults', action='store_true', help="Disable faults on startup")
-
- parser.add_argument('--ca_file', type=str, required=True, help="TLS CA PEM file")
-
- parser.add_argument('--cert_file', type=str, required=True, help="TLS Server PEM file")
-
- args = parser.parse_args()
- if args.verbose:
- logging.basicConfig(level=logging.DEBUG)
-
- if args.fault:
- if args.fault not in SUPPORTED_FAULT_TYPES:
- print("Unsupported fault type %s, supports types are %s" % (args.fault, SUPPORTED_FAULT_TYPES))
- sys.exit(1)
-
- kms_http_common.fault_type = args.fault
-
- if args.disable_faults:
- kms_http_common.disable_faults = True
-
- kms_http_common.run(args.port, args.cert_file, args.ca_file, GcpKmsHandler)
-
-
-if __name__ == '__main__':
- main()
diff --git a/jstests/client_encrypt/lib/mock_kms.js b/jstests/client_encrypt/lib/mock_kms.js
deleted file mode 100644
index d1fd64abc3d..00000000000
--- a/jstests/client_encrypt/lib/mock_kms.js
+++ /dev/null
@@ -1,188 +0,0 @@
-/**
- * Starts a mock KMS Server to test
- * FLE encryption and decryption.
- */
-
-// These faults must match the list of faults in kms_http_server.py, see the
-// SUPPORTED_FAULT_TYPES list in kms_http_server.py
-const FAULT_ENCRYPT = "fault_encrypt";
-const FAULT_ENCRYPT_CORRECT_FORMAT = "fault_encrypt_correct_format";
-const FAULT_ENCRYPT_WRONG_FIELDS = "fault_encrypt_wrong_fields";
-const FAULT_ENCRYPT_BAD_BASE64 = "fault_encrypt_bad_base64";
-const FAULT_DECRYPT = "fault_decrypt";
-const FAULT_DECRYPT_CORRECT_FORMAT = "fault_decrypt_correct_format";
-const FAULT_DECRYPT_WRONG_KEY = "fault_decrypt_wrong_key";
-const FAULT_OAUTH = "fault_oauth";
-const FAULT_OAUTH_CORRECT_FORMAT = "fault_oauth_correct_format";
-
-const DISABLE_FAULTS = "disable_faults";
-const ENABLE_FAULTS = "enable_faults";
-
-class MockKMSServerAWS {
- /**
- * Create a new webserver.
- *
- * @param {string} fault_type
- * @param {bool} disableFaultsOnStartup optionally disable fault on startup
- */
- constructor(fault_type, disableFaultsOnStartup) {
- this.python = "python3";
- this.disableFaultsOnStartup = disableFaultsOnStartup || false;
- this.fault_type = fault_type;
-
- if (_isWindows()) {
- this.python = "python.exe";
- }
-
- print("Using python interpreter: " + this.python);
-
- this.ca_file = "jstests/libs/ca.pem";
- this.server_cert_file = "jstests/libs/server.pem";
- this.web_server_py = "jstests/client_encrypt/lib/kms_http_server.py";
- this.control_py = "jstests/client_encrypt/lib/kms_http_control.py";
- this.port = -1;
- }
-
- /**
- * Start a web server
- */
- start() {
- this.port = allocatePort();
- print("Mock Web server is listening on port: " + this.port);
-
- let args = [
- this.python,
- "-u",
- this.web_server_py,
- "--port=" + this.port,
- "--ca_file=" + this.ca_file,
- "--cert_file=" + this.server_cert_file
- ];
- if (this.fault_type) {
- args.push("--fault=" + this.fault_type);
- if (this.disableFaultsOnStartup) {
- args.push("--disable-faults");
- }
- }
-
- clearRawMongoProgramOutput();
-
- this.pid = _startMongoProgram({args: args});
- assert(checkProgram(this.pid));
-
- assert.soon(function() {
- return rawMongoProgramOutput().search("Mock KMS Web Server Listening") !== -1;
- });
- sleep(1000);
- print("Mock KMS Server successfully started");
- }
-
- _runCommand(cmd) {
- let ret = 0;
- if (_isWindows()) {
- ret = runProgram('cmd.exe', '/c', cmd);
- } else {
- ret = runProgram('/bin/sh', '-c', cmd);
- }
-
- assert.eq(ret, 0);
- }
-
- /**
- * Query the HTTP server.
- *
- * @param {string} query type
- *
- * @return {object} Object representation of JSON from the server.
- */
- query(query) {
- const out_file = "out_" + this.port + ".txt";
- const python_command = this.python + " -u " + this.control_py + " --port=" + this.port +
- " --ca_file=" + this.ca_file + " --query=" + query + " > " + out_file;
-
- this._runCommand(python_command);
-
- const result = cat(out_file);
-
- try {
- return JSON.parse(result);
- } catch (e) {
- jsTestLog("Failed to parse: " + result + "\n" + result);
- throw e;
- }
- }
-
- /**
- * Control the HTTP server.
- *
- * @param {string} query type
- */
- control(query) {
- const python_command = this.python + " -u " + this.control_py + " --port=" + this.port +
- " --ca_file=" + this.ca_file + " --query=" + query;
-
- this._runCommand(python_command);
- }
-
- /**
- * Disable Faults
- */
- disableFaults() {
- this.control(DISABLE_FAULTS);
- }
-
- /**
- * Enable Faults
- */
- enableFaults() {
- this.control(ENABLE_FAULTS);
- }
-
- /**
- * Query the stats page for the HTTP server.
- *
- * @return {object} Object representation of JSON from the server.
- */
- queryStats() {
- return this.query("stats");
- }
-
- /**
- * Get the URL. Prefixed with https://
- *
- * @return {string} url of http server
- */
- getURL() {
- return "https://localhost:" + this.port;
- }
-
- /**
- * Get the endpoint. A "<host>:<port>".
- *
- * @return {string} url of http server
- */
- getEndpoint() {
- return "localhost:" + this.port;
- }
-
- /**
- * Stop the web server
- */
- stop() {
- stopMongoProgramByPid(this.pid);
- }
-}
-
-class MockKMSServerGCP extends MockKMSServerAWS {
- constructor(fault_type, disableFaultsOnStartup) {
- super(fault_type, disableFaultsOnStartup);
- this.web_server_py = "jstests/client_encrypt/lib/kms_http_server_gcp.py";
- }
-}
-
-class MockKMSServerAzure extends MockKMSServerAWS {
- constructor(fault_type, disableFaultsOnStartup) {
- super(fault_type, disableFaultsOnStartup);
- this.web_server_py = "jstests/client_encrypt/lib/kms_http_server_azure.py";
- }
-}
diff --git a/src/mongo/shell/SConscript b/src/mongo/shell/SConscript
index 1179246d35c..1bae6d96446 100644
--- a/src/mongo/shell/SConscript
+++ b/src/mongo/shell/SConscript
@@ -148,33 +148,34 @@ env.Library(
],
)
+env.Library(
+ target="kms_idl",
+ source=[
+ "kms.idl",
+ ],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/idl/idl_parser',
+ ],
+)
+
if get_option('ssl') == 'on':
kmsEnv = env.Clone()
- kmsEnv.InjectThirdParty(libraries=['kms-message'])
-
kmsEnv.Library(
target="kms",
source=[
"kms.cpp",
- "kms_aws.cpp",
- "kms_azure.cpp",
- "kms_gcp.cpp",
"kms_local.cpp",
- "kms_network.cpp",
- "kms.idl",
],
LIBDEPS=[
'$BUILD_DIR/mongo/base/secure_allocator',
+ 'kms_idl',
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/crypto/aead_encryption',
'$BUILD_DIR/mongo/db/commands/test_commands_enabled',
- '$BUILD_DIR/mongo/util/net/network',
- '$BUILD_DIR/mongo/util/net/ssl_manager',
- '$BUILD_DIR/mongo/util/net/ssl_options',
- '$BUILD_DIR/third_party/shim_kms_message',
],
)
@@ -205,7 +206,6 @@ if get_option('ssl') == 'on':
target="encrypted_dbclient",
source=[
"encrypted_dbclient_base.cpp",
- "fle_shell_options.idl",
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/client/clientdriver_minimal',
diff --git a/src/mongo/shell/encrypted_dbclient_base.cpp b/src/mongo/shell/encrypted_dbclient_base.cpp
index db14d4f8fc2..844c44fea36 100644
--- a/src/mongo/shell/encrypted_dbclient_base.cpp
+++ b/src/mongo/shell/encrypted_dbclient_base.cpp
@@ -58,7 +58,6 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
-#include "mongo/shell/encrypted_shell_options.h"
#include "mongo/shell/kms.h"
#include "mongo/shell/kms_gen.h"
#include "mongo/shell/shell_options.h"
@@ -66,8 +65,6 @@
namespace mongo {
-EncryptedShellGlobalParams encryptedShellGlobalParams;
-
namespace {
constexpr Duration kCacheInvalidationTime = Minutes(1);
@@ -807,7 +804,7 @@ std::unique_ptr<DBClientBase> createEncryptedDBClientBase(std::unique_ptr<DBClie
static constexpr auto keyVaultClientFieldId = "keyVaultClient";
- if (!arg.isObject() && encryptedShellGlobalParams.awsAccessKeyId.empty()) {
+ if (!arg.isObject()) {
return conn;
}
@@ -815,32 +812,7 @@ std::unique_ptr<DBClientBase> createEncryptedDBClientBase(std::unique_ptr<DBClie
JS::RootedValue client(cx);
JS::RootedValue collection(cx);
- if (!arg.isObject()) {
- // If arg is not an object, but one of the required encryptedShellGlobalParams
- // is defined, the user is trying to start an encrypted client with command line
- // parameters.
-
- AwsKMS awsKms = AwsKMS(encryptedShellGlobalParams.awsAccessKeyId,
- encryptedShellGlobalParams.awsSecretAccessKey);
-
- awsKms.setUrl(StringData(encryptedShellGlobalParams.awsKmsURL));
-
- awsKms.setSessionToken(StringData(encryptedShellGlobalParams.awsSessionToken));
-
- KmsProviders kmsProviders;
- kmsProviders.setAws(awsKms);
-
- // The mongoConnection object will never be null.
- // If the encrypted shell is started through command line parameters, then the user must
- // default to the implicit connection for the keyvault collection.
- client.setObjectOrNull(mongoConnection.get());
-
- // Because we cannot add a schemaMap object through the command line, we set the
- // schemaMap object in ClientSideFLEOptions to be null so we know to always use
- // remote schemas.
- encryptionOptions = ClientSideFLEOptions(encryptedShellGlobalParams.keyVaultNamespace,
- std::move(kmsProviders));
- } else {
+ {
uassert(ErrorCodes::BadValue,
"Collection object must be passed to Field Level Encryption Options",
arg.isObject());
diff --git a/src/mongo/shell/encrypted_dbclient_base.h b/src/mongo/shell/encrypted_dbclient_base.h
index 76a24afc10f..4f00b5b0e4b 100644
--- a/src/mongo/shell/encrypted_dbclient_base.h
+++ b/src/mongo/shell/encrypted_dbclient_base.h
@@ -51,7 +51,6 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
-#include "mongo/shell/encrypted_shell_options.h"
#include "mongo/shell/kms.h"
#include "mongo/shell/kms_gen.h"
#include "mongo/shell/shell_options.h"
diff --git a/src/mongo/shell/encrypted_shell_options.h b/src/mongo/shell/encrypted_shell_options.h
deleted file mode 100644
index b4b30aba2fe..00000000000
--- a/src/mongo/shell/encrypted_shell_options.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Copyright (C) 2019-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <string>
-
-namespace mongo {
-
-struct EncryptedShellGlobalParams {
- std::string awsAccessKeyId;
- std::string awsSecretAccessKey;
- std::string awsSessionToken;
- std::string keyVaultNamespace;
- std::string awsKmsURL;
-};
-
-extern EncryptedShellGlobalParams encryptedShellGlobalParams;
-} // namespace mongo
diff --git a/src/mongo/shell/fle_shell_options.idl b/src/mongo/shell/fle_shell_options.idl
deleted file mode 100644
index 64578aaa69b..00000000000
--- a/src/mongo/shell/fle_shell_options.idl
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2019-present MongoDB, Inc.
-
-global:
- cpp_namespace: "mongo"
- configs:
- section: 'FLE AWS Options'
- source: [ cli ]
- cpp_includes:
- - mongo/shell/encrypted_shell_options.h
-
-configs:
- "awsAccessKeyId":
- description: "AWS Access Key for FLE Amazon KMS"
- arg_vartype: String
- cpp_varname: encryptedShellGlobalParams.awsAccessKeyId
- requires: [ "awsSecretAccessKey", "keyVaultNamespace" ]
- "awsSecretAccessKey":
- description: "AWS Secret Key for FLE Amazon KMS"
- arg_vartype: String
- cpp_varname: encryptedShellGlobalParams.awsSecretAccessKey
- redact: true
- requires: [ "awsAccessKeyId", "keyVaultNamespace" ]
- "awsSessionToken":
- description: "Optional AWS Session Token ID"
- arg_vartype: String
- cpp_varname: encryptedShellGlobalParams.awsSessionToken
- requires: [ "awsAccessKeyId", "awsSecretAccessKey", "keyVaultNamespace" ]
- "keyVaultNamespace":
- description: "database.collection to store encrypted FLE parameters"
- arg_vartype: String
- cpp_varname: encryptedShellGlobalParams.keyVaultNamespace
- requires: [ "awsAccessKeyId", "awsSecretAccessKey" ]
- "kmsURL":
- description: "Test parameter to override the URL for KMS"
- arg_vartype: String
- cpp_varname: encryptedShellGlobalParams.awsKmsURL
- requires: [ "awsAccessKeyId", "awsSecretAccessKey", "keyVaultNamespace" ]
diff --git a/src/mongo/shell/kms.cpp b/src/mongo/shell/kms.cpp
index 792be3ab1f3..f379c5f43e2 100644
--- a/src/mongo/shell/kms.cpp
+++ b/src/mongo/shell/kms.cpp
@@ -37,20 +37,6 @@
namespace mongo {
-HostAndPort parseUrl(StringData url) {
- // Treat the URL as a host and port
- // URL: https://(host):(port)
- //
- constexpr StringData urlPrefix = "https://"_sd;
- uassert(51140,
- str::stream() << "KMS URL must start with https://, URL: " << url,
- url.startsWith(urlPrefix));
-
- StringData hostAndPort = url.substr(urlPrefix.size());
-
- return HostAndPort(hostAndPort);
-}
-
BSONObj KMSService::encryptDataKeyByString(ConstDataRange cdr, StringData keyId) {
uasserted(5380101,
str::stream() << "Customer Master Keys for " << name()
diff --git a/src/mongo/shell/kms.h b/src/mongo/shell/kms.h
index 0560100feea..a67b82db283 100644
--- a/src/mongo/shell/kms.h
+++ b/src/mongo/shell/kms.h
@@ -37,6 +37,7 @@
#include "mongo/base/secure_allocator.h"
#include "mongo/base/string_data.h"
#include "mongo/bson/bsonobj.h"
+#include "mongo/crypto/symmetric_key.h"
#include "mongo/shell/kms_gen.h"
#include "mongo/stdx/unordered_map.h"
#include "mongo/util/net/hostandport.h"
@@ -84,6 +85,8 @@ public:
* needs to be store in the key vault.
*/
virtual BSONObj encryptDataKeyByBSONObj(ConstDataRange cdr, BSONObj keyId);
+
+ virtual SymmetricKey& getMasterKey() = 0;
};
/**
@@ -131,11 +134,4 @@ private:
static stdx::unordered_map<KMSProviderEnum, std::unique_ptr<KMSServiceFactory>> _factories;
};
-/**
- * Parse a basic url of "https://host:port" to a HostAndPort.
- *
- * Does not support URL encoding or anything else.
- */
-HostAndPort parseUrl(StringData url);
-
} // namespace mongo
diff --git a/src/mongo/shell/kms.idl b/src/mongo/shell/kms.idl
index 5124a22c26f..80875714545 100644
--- a/src/mongo/shell/kms.idl
+++ b/src/mongo/shell/kms.idl
@@ -37,71 +37,9 @@ enums:
description: "Enumeration of supported KMS Providers"
type: string
values:
- aws: "aws"
- azure: "azure"
- gcp: "gcp"
local: "local"
structs:
- awsKMSError:
- description: "AWS KMS error"
- strict: false
- fields:
- __type:
- type: string
- cpp_name: type
- Message: string
-
- # Options passed to Mongo() javascript constructor
- awsKMS:
- description: "AWS KMS config"
- fields:
- accessKeyId: string
- secretAccessKey: string
- sessionToken:
- type: string
- optional: true
- url:
- type: string
- optional: true
-
- azureKMSError:
- description: "Azure KMS Error"
- strict: false
- fields:
- code: string
- message: string
-
- # Options passed to Mongo() javascript constructor
- azureKMS:
- description: "Azure KMS config"
- fields:
- tenantId: string
- clientId: string
- clientSecret: string
- identityPlatformEndpoint:
- type: string
- optional: true
-
- # Documented here: https://cloud.google.com/apis/design/errors#http_mapping
- gcpKMSError:
- description: "GCP KMS Error"
- strict: false
- fields:
- code: int
- message: string
- status: string
-
- # Options passed to Mongo() javascript constructor
- gcpKMS:
- description: "GCP KMS config"
- fields:
- email: string
- endpoint:
- type: string
- optional: true
- privateKey: string
-
# Options passed to Mongo() javascript constructor
localKMS:
description: "Local KMS config"
@@ -112,15 +50,6 @@ structs:
description: "Supported KMS Providers"
strict: true
fields:
- aws:
- type: awsKMS
- optional: true
- azure:
- type: azureKMS
- optional: true
- gcp:
- type: gcpKMS
- optional: true
local:
type: localKMS
optional: true
@@ -141,121 +70,6 @@ structs:
type: bool
optional: true
- awsEncryptResponse:
- description: "Response from AWS KMS Encrypt request, i.e. TrentService.Encrypt"
- strict: false
- fields:
- CiphertextBlob:
- type: string
- KeyId:
- type: string
-
- awsDecryptResponse:
- description: "Response from AWS KMS Decrypt request, i.e. TrentService.Decrypt"
- # Nov 13, 2019 they added EncryptionAlgorithm but it is not documented
- strict: false
- fields:
- Plaintext:
- type: string
- KeyId:
- type: string
-
- awsMasterKey:
- description: "AWS KMS Key Store Description"
- fields:
- provider:
- type: string
- default: '"aws"'
- key:
- type: string
- region:
- type: string
- endpoint:
- type: string
- optional: true
-
- awsMasterKeyAndMaterial:
- description: "AWS KMS Key Material Description"
- fields:
- keyMaterial:
- type: bindata_generic
- masterKey:
- type: awsMasterKey
-
- azureEncryptResponse:
- description: "Response from Azure KMS wrapKey request"
- strict: false
- fields:
- kid: string
- value: string
-
- azureDecryptResponse:
- description: "Response from Azure KMS unwrapKey request"
- strict: false
- fields:
- kid: string
- value: string
-
- azureMasterKey:
- description: "Azure KMS Key Store Description"
- fields:
- provider:
- type: string
- default: '"azure"'
- keyName: string
- keyVersion:
- type: string
- optional: true
- keyVaultEndpoint: string
-
- azureMasterKeyAndMaterial:
- description: "Azure KMS Key Material Description"
- fields:
- keyMaterial: bindata_generic
- masterKey: azureMasterKey
-
- gcpEncryptResponse:
- description: "Response from GCP KMS Encrypt request"
- strict: false
- fields:
- name: string
- ciphertext: string
-
- gcpDecryptResponse:
- description: "Response from GCP KMS Decrypt request"
- strict: false
- fields:
- plaintext: string
-
- gcpMasterKey:
- description: "GCP KMS Key Store Description"
- fields:
- provider:
- type: string
- default: '"gcp"'
- keyName:
- type: string
- keyRing:
- type: string
- keyVersion:
- type: string
- optional: true
- location:
- type: string
- projectId:
- type: string
- endpoint:
- type: string
- optional: true
-
- gcpMasterKeyAndMaterial:
- description: "GCP KMS Key Material Description"
- fields:
- keyMaterial:
- type: bindata_generic
- masterKey:
- type: gcpMasterKey
-
localMasterKey:
description: "Local KMS Key Store Description"
fields:
@@ -287,31 +101,4 @@ structs:
type: array<string>
ignore: true
- # Defined in 4.2.2. in RFC 6749
- OAuthResponse:
- description: "An oauth response with a token"
- strict: false
- fields:
- access_token: string
- token_type: string
- # Expires_in is in seconds
- expires_in:
- type: int
- optional: true
- scope:
- type: string
- optional: true
-
- # Defined in 4.2.2.1. in RFC 6749
- OAuthErrorResponse:
- description: "An oauth response with a token"
- strict: false
- fields:
- error: string
- error_description:
- type: string
- optional: true
- error_uri:
- type: string
- optional: true
diff --git a/src/mongo/shell/kms_aws.cpp b/src/mongo/shell/kms_aws.cpp
deleted file mode 100644
index 5d81566348a..00000000000
--- a/src/mongo/shell/kms_aws.cpp
+++ /dev/null
@@ -1,322 +0,0 @@
-/**
- * Copyright (C) 2019-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-
-#include <kms_message/kms_message.h>
-
-#include <stdlib.h>
-
-#include "mongo/base/init.h"
-#include "mongo/base/parse_number.h"
-#include "mongo/base/secure_allocator.h"
-#include "mongo/base/status_with.h"
-#include "mongo/bson/json.h"
-#include "mongo/shell/kms.h"
-#include "mongo/shell/kms_gen.h"
-#include "mongo/shell/kms_network.h"
-#include "mongo/util/base64.h"
-#include "mongo/util/kms_message_support.h"
-#include "mongo/util/net/hostandport.h"
-#include "mongo/util/net/ssl_manager.h"
-#include "mongo/util/net/ssl_options.h"
-#include "mongo/util/text.h"
-#include "mongo/util/time_support.h"
-
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl
-
-
-namespace mongo {
-namespace {
-
-/**
- * AWS configuration settings
- */
-struct AWSConfig {
- // AWS_ACCESS_KEY_ID
- std::string accessKeyId;
-
- // AWS_SECRET_ACCESS_KEY
- SecureString secretAccessKey;
-
- // Optional AWS_SESSION_TOKEN for AWS STS tokens
- boost::optional<std::string> sessionToken;
-};
-
-constexpr auto kAwsKms = "aws"_sd;
-
-/**
- * Manages SSL information and config for how to talk to AWS KMS.
- */
-class AWSKMSService final : public KMSService {
-public:
- AWSKMSService() = default;
-
- StringData name() const {
- return kAwsKms;
- }
-
- static std::unique_ptr<KMSService> create(const AwsKMS& config);
-
- SecureVector<uint8_t> decrypt(ConstDataRange cdr, BSONObj masterKey) final;
-
- BSONObj encryptDataKeyByString(ConstDataRange cdr, StringData keyId) final;
-
-private:
- std::vector<uint8_t> encrypt(ConstDataRange cdr, StringData kmsKeyId);
-
- void initRequest(kms_request_t* request, StringData host, StringData region);
-
-private:
- // SSL Manager
- std::shared_ptr<SSLManagerInterface> _sslManager;
-
- // Server to connect to
- HostAndPort _server;
-
- // AWS configuration settings
- AWSConfig _config;
-};
-
-void uassertKmsRequestInternal(kms_request_t* request, bool ok) {
- if (!ok) {
- const char* msg = kms_request_get_error(request);
- uasserted(51135, str::stream() << "Internal AWS KMS Error: " << msg);
- }
-}
-
-#define uassertKmsRequest(X) uassertKmsRequestInternal(request, (X));
-
-void AWSKMSService::initRequest(kms_request_t* request, StringData host, StringData region) {
-
- // use current time
- uassertKmsRequest(kms_request_set_date(request, nullptr));
-
- uassertKmsRequest(kms_request_set_region(request, region.toString().c_str()));
-
- // kms is always the name of the service
- uassertKmsRequest(kms_request_set_service(request, "kms"));
-
- uassertKmsRequest(kms_request_set_access_key_id(request, _config.accessKeyId.c_str()));
- uassertKmsRequest(kms_request_set_secret_key(request, _config.secretAccessKey->c_str()));
-
- // Set host to be the host we are targeting instead of defaulting to kms.<region>.amazonaws.com
- uassertKmsRequest(kms_request_add_header_field(request, "Host", host.toString().c_str()));
-
- if (!_config.sessionToken.value_or("").empty()) {
- // TODO: move this into kms-message
- uassertKmsRequest(kms_request_add_header_field(
- request, "X-Amz-Security-Token", _config.sessionToken.value().c_str()));
- }
-}
-
-
-/**
- * Takes in a CMK of the format arn:partition:service:region:account-id:resource (minimum). We
- * care about extracting the region. This function ensures that there are at least 6 partitions,
- * parses the provider, and returns a pair of provider and the region.
- */
-std::string parseCMK(StringData cmk) {
- std::vector<std::string> cmkTokenized = StringSplitter::split(cmk.toString(), ":");
- uassert(31040, "Invalid AWS KMS Customer Master Key.", cmkTokenized.size() > 5);
- return cmkTokenized[3];
-}
-
-HostAndPort getDefaultHost(StringData region) {
- std::string hostname = str::stream() << "kms." << region << ".amazonaws.com";
- return HostAndPort(hostname, 443);
-}
-
-std::vector<uint8_t> AWSKMSService::encrypt(ConstDataRange cdr, StringData kmsKeyId) {
- auto request =
- UniqueKmsRequest(kms_encrypt_request_new(reinterpret_cast<const uint8_t*>(cdr.data()),
- cdr.length(),
- kmsKeyId.toString().c_str(),
- NULL));
-
- auto region = parseCMK(kmsKeyId);
-
- if (_server.empty()) {
- _server = getDefaultHost(region);
- }
-
- initRequest(request.get(), _server.host(), region);
-
- auto buffer = UniqueKmsCharBuffer(kms_request_get_signed(request.get()));
- auto buffer_len = strlen(buffer.get());
-
- KMSNetworkConnection connection(_sslManager.get());
- auto response = connection.makeOneRequest(_server, ConstDataRange(buffer.get(), buffer_len));
-
- auto body = kms_response_get_body(response.get(), nullptr);
-
- BSONObj obj = fromjson(body);
-
- auto field = obj["__type"];
-
- if (!field.eoo()) {
- AwsKMSError awsResponse;
- try {
- awsResponse = AwsKMSError::parse(IDLParserContext("awsEncryptError"), obj);
- } catch (DBException& dbe) {
- uasserted(51274,
- str::stream() << "AWS KMS failed to parse error message: " << dbe.toString()
- << ", Response : " << obj);
- }
-
- uasserted(51224,
- str::stream() << "AWS KMS failed to encrypt: " << awsResponse.getType() << " : "
- << awsResponse.getMessage());
- }
-
- auto awsResponse = AwsEncryptResponse::parse(IDLParserContext("awsEncryptResponse"), obj);
-
- auto blobStr = base64::decode(awsResponse.getCiphertextBlob().toString());
-
- return kmsResponseToVector(blobStr);
-}
-
-BSONObj AWSKMSService::encryptDataKeyByString(ConstDataRange cdr, StringData keyId) {
- auto dataKey = encrypt(cdr, keyId);
-
- AwsMasterKey masterKey;
- masterKey.setKey(keyId);
- masterKey.setRegion(parseCMK(keyId));
- masterKey.setEndpoint(boost::optional<StringData>(_server.toString()));
-
- AwsMasterKeyAndMaterial keyAndMaterial;
- keyAndMaterial.setKeyMaterial(dataKey);
- keyAndMaterial.setMasterKey(masterKey);
-
-
- return keyAndMaterial.toBSON();
-}
-
-SecureVector<uint8_t> AWSKMSService::decrypt(ConstDataRange cdr, BSONObj masterKey) {
- auto awsMasterKey = AwsMasterKey::parse(IDLParserContext("awsMasterKey"), masterKey);
-
- auto request = UniqueKmsRequest(kms_decrypt_request_new(
- reinterpret_cast<const uint8_t*>(cdr.data()), cdr.length(), nullptr));
-
- if (_server.empty()) {
- _server = getDefaultHost(awsMasterKey.getRegion());
- }
-
- initRequest(request.get(), _server.host(), awsMasterKey.getRegion());
-
- auto buffer = UniqueKmsCharBuffer(kms_request_get_signed(request.get()));
- auto buffer_len = strlen(buffer.get());
- KMSNetworkConnection connection(_sslManager.get());
- auto response = connection.makeOneRequest(_server, ConstDataRange(buffer.get(), buffer_len));
-
- auto body = kms_response_get_body(response.get(), nullptr);
-
- BSONObj obj = fromjson(body);
-
- auto field = obj["__type"];
-
- if (!field.eoo()) {
- AwsKMSError awsResponse;
- try {
- awsResponse = AwsKMSError::parse(IDLParserContext("awsDecryptError"), obj);
- } catch (DBException& dbe) {
- uasserted(51275,
- str::stream() << "AWS KMS failed to parse error message: " << dbe.toString()
- << ", Response : " << obj);
- }
-
- uasserted(51225,
- str::stream() << "AWS KMS failed to decrypt: " << awsResponse.getType() << " : "
- << awsResponse.getMessage());
- }
-
- auto awsResponse = AwsDecryptResponse::parse(IDLParserContext("awsDecryptResponse"), obj);
-
- auto blobStr = base64::decode(awsResponse.getPlaintext().toString());
-
- return kmsResponseToSecureVector(blobStr);
-}
-
-boost::optional<std::string> toString(boost::optional<StringData> str) {
- if (str) {
- return {str.value().toString()};
- }
- return boost::none;
-}
-
-std::unique_ptr<KMSService> AWSKMSService::create(const AwsKMS& config) {
- auto awsKMS = std::make_unique<AWSKMSService>();
-
- SSLParams params;
- getSSLParamsForNetworkKMS(&params);
-
- // Leave the CA file empty so we default to system CA but for local testing allow it to inherit
- // the CA file.
- if (!config.getUrl().value_or("").empty()) {
- params.sslCAFile = sslGlobalParams.sslCAFile;
- awsKMS->_server = parseUrl(config.getUrl().value());
- }
-
- awsKMS->_sslManager = SSLManagerInterface::create(params, false);
-
- awsKMS->_config.accessKeyId = config.getAccessKeyId().toString();
-
- awsKMS->_config.secretAccessKey = config.getSecretAccessKey().toString();
-
- awsKMS->_config.sessionToken = toString(config.getSessionToken());
-
- return awsKMS;
-}
-
-/**
- * Factory for AWSKMSService if user specifies aws config to mongo() JS constructor.
- */
-class AWSKMSServiceFactory final : public KMSServiceFactory {
-public:
- AWSKMSServiceFactory() = default;
- ~AWSKMSServiceFactory() = default;
-
- std::unique_ptr<KMSService> create(const BSONObj& config) final {
- auto field = config[KmsProviders::kAwsFieldName];
- if (field.eoo()) {
- return nullptr;
- }
- auto obj = field.Obj();
- return AWSKMSService::create(AwsKMS::parse(IDLParserContext("root"), obj));
- }
-};
-
-} // namespace
-
-MONGO_INITIALIZER(KMSRegisterAWS)(::mongo::InitializerContext*) {
- kms_message_init();
- KMSServiceController::registerFactory(KMSProviderEnum::aws,
- std::make_unique<AWSKMSServiceFactory>());
-}
-
-} // namespace mongo
diff --git a/src/mongo/shell/kms_azure.cpp b/src/mongo/shell/kms_azure.cpp
deleted file mode 100644
index 459e1f812ae..00000000000
--- a/src/mongo/shell/kms_azure.cpp
+++ /dev/null
@@ -1,301 +0,0 @@
-/**
- * Copyright (C) 2021-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include "kms_message/kms_request.h"
-#include "mongo/shell/kms_gen.h"
-
-#include "mongo/platform/basic.h"
-
-#include <fmt/format.h>
-#include <kms_message/kms_azure_request.h>
-#include <kms_message/kms_b64.h>
-#include <kms_message/kms_message.h>
-
-#include "mongo/bson/json.h"
-#include "mongo/shell/kms.h"
-#include "mongo/shell/kms_network.h"
-#include "mongo/util/net/hostandport.h"
-
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::logv2::LogComponent::kControl
-
-
-namespace mongo {
-namespace {
-
-using namespace fmt::literals;
-
-constexpr auto kAzureKms = "azure"_sd;
-
-// Default endpoints for Azure
-constexpr auto kDefaultIdentityPlatformEndpoint = "login.microsoftonline.com"_sd;
-// Since scope is passed as URL parameter, it needs to be escaped and kms_message does not escape
-// it.
-constexpr auto kDefaultOAuthScope = "https%3A%2F%2Fvault.azure.net%2F.default"_sd;
-
-struct AzureConfig {
- // ID for the user in Azure
- std::string tenantId;
-
- // ID for the application in Azure
- std::string clientId;
-
- // Secret key for the application in Azure
- std::string clientSecret;
-
- // Options to pass to kms-message
- UniqueKmsRequestOpts opts;
-};
-
-/**
- * Manages OAuth token requests and caching
- */
-class AzureKMSOAuthService final : public KMSOAuthService {
-public:
- AzureKMSOAuthService(const AzureConfig& config,
- HostAndPort endpoint,
- std::shared_ptr<SSLManagerInterface> sslManager)
- : KMSOAuthService(endpoint, sslManager), _config(config) {}
-
-protected:
- UniqueKmsRequest getOAuthRequest() final {
- auto request =
- UniqueKmsRequest(kms_azure_request_oauth_new(_oAuthEndpoint.host().c_str(),
- kDefaultOAuthScope.toString().c_str(),
- _config.tenantId.c_str(),
- _config.clientId.c_str(),
- _config.clientSecret.c_str(),
- _config.opts.get()));
-
- const char* msg = kms_request_get_error(request.get());
- uassert(5265101, "Internal Azure KMS Error: {}"_format(msg), msg == nullptr);
-
- return request;
- }
-
-private:
- const AzureConfig& _config;
-};
-
-/**
- * Manages SSL information and config for how to talk to Azure KMS.
- */
-class AzureKMSService final : public KMSService {
-public:
- AzureKMSService() = default;
-
- static std::unique_ptr<KMSService> create(const AzureKMS& config);
-
- SecureVector<uint8_t> decrypt(ConstDataRange cdr, BSONObj masterKey) final;
-
- BSONObj encryptDataKeyByBSONObj(ConstDataRange cdr, BSONObj keyId) final;
-
- StringData name() const final {
- return kAzureKms;
- }
-
-private:
- template <typename AzureResponseT>
- std::unique_ptr<uint8_t, decltype(std::free)*> makeRequest(kms_request_t* request,
- const HostAndPort& keyVaultEndpoint,
- size_t* raw_len);
-
-private:
- // SSL Manager
- std::shared_ptr<SSLManagerInterface> _sslManager;
-
- // Azure configuration settings
- AzureConfig _config;
-
- // Service fr managing OAuth requests and token cache
- std::unique_ptr<AzureKMSOAuthService> _oauthService;
-};
-
-std::unique_ptr<KMSService> AzureKMSService::create(const AzureKMS& config) {
- auto azureKMS = std::make_unique<AzureKMSService>();
-
- SSLParams params;
- getSSLParamsForNetworkKMS(&params);
-
- HostAndPort identityPlatformHostAndPort(kDefaultIdentityPlatformEndpoint.toString(), 443);
- if (config.getIdentityPlatformEndpoint().has_value()) {
- // Leave the CA file empty so we default to system CA but for local testing allow it to
- // inherit the CA file.
- params.sslCAFile = sslGlobalParams.sslCAFile;
- identityPlatformHostAndPort = parseUrl(config.getIdentityPlatformEndpoint().value());
- }
-
- azureKMS->_sslManager = SSLManagerInterface::create(params, false);
-
- azureKMS->_config.opts = UniqueKmsRequestOpts(kms_request_opt_new());
- kms_request_opt_set_provider(azureKMS->_config.opts.get(), KMS_REQUEST_PROVIDER_AZURE);
-
- azureKMS->_config.clientSecret = config.getClientSecret().toString();
-
- azureKMS->_config.clientId = config.getClientId().toString();
-
- azureKMS->_config.tenantId = config.getTenantId().toString();
-
- azureKMS->_oauthService = std::make_unique<AzureKMSOAuthService>(
- azureKMS->_config, identityPlatformHostAndPort, azureKMS->_sslManager);
-
- return azureKMS;
-}
-
-HostAndPort parseEndpoint(StringData endpoint) {
- HostAndPort host(endpoint);
-
- if (host.hasPort()) {
- return host;
- }
-
- return {host.host(), 443};
-}
-
-template <typename AzureResponseT>
-std::unique_ptr<uint8_t, decltype(std::free)*> AzureKMSService::makeRequest(
- kms_request_t* request, const HostAndPort& keyVaultEndpoint, size_t* raw_len) {
- auto buffer = UniqueKmsCharBuffer(kms_request_to_string(request));
- auto buffer_len = strlen(buffer.get());
- KMSNetworkConnection connection(_sslManager.get());
- auto response =
- connection.makeOneRequest(keyVaultEndpoint, ConstDataRange(buffer.get(), buffer_len));
-
- auto body = kms_response_get_body(response.get(), nullptr);
-
- BSONObj obj = fromjson(body);
-
- if (obj.hasField("error")) {
- AzureKMSError azureResponse;
- try {
- azureResponse =
- AzureKMSError::parse(IDLParserContext("azureError"), obj["error"].Obj());
- } catch (DBException& dbe) {
- uasserted(5265102,
- "Azure KMS failed to parse error message: {}, Response : {}"_format(
- dbe.toString(), obj.toString()));
- }
-
- uasserted(5265103,
- "Azure KMS failed, response: {} : {}"_format(azureResponse.getCode(),
- azureResponse.getMessage()));
- }
-
- auto azureResponse = AzureResponseT::parse(IDLParserContext("azureResponse"), obj);
-
- auto b64Url = azureResponse.getValue().toString();
- std::unique_ptr<uint8_t, decltype(std::free)*> raw_str(
- kms_message_b64url_to_raw(b64Url.c_str(), raw_len), std::free);
- uassert(5265104, "Azure KMS failed to convert key blob from base64 URL.", raw_str != nullptr);
-
- return raw_str;
-}
-
-
-SecureVector<uint8_t> AzureKMSService::decrypt(ConstDataRange cdr, BSONObj masterKey) {
- auto azureMasterKey = AzureMasterKey::parse(IDLParserContext("azureMasterKey"), masterKey);
- StringData bearerToken = _oauthService->getBearerToken();
-
- HostAndPort keyVaultEndpoint = parseEndpoint(azureMasterKey.getKeyVaultEndpoint());
-
- auto request = UniqueKmsRequest(kms_azure_request_unwrapkey_new(
- keyVaultEndpoint.host().c_str(),
- bearerToken.toString().c_str(),
- azureMasterKey.getKeyName().toString().c_str(),
- azureMasterKey.getKeyVersion().value_or(""_sd).toString().c_str(),
- reinterpret_cast<const uint8_t*>(cdr.data()),
- cdr.length(),
- _config.opts.get()));
-
- size_t raw_len;
- auto raw_str = makeRequest<AzureDecryptResponse>(request.get(), keyVaultEndpoint, &raw_len);
-
- return kmsResponseToSecureVector(
- StringData(reinterpret_cast<const char*>(raw_str.get()), raw_len));
-}
-
-BSONObj AzureKMSService::encryptDataKeyByBSONObj(ConstDataRange cdr, BSONObj keyId) {
- StringData bearerToken = _oauthService->getBearerToken();
- AzureMasterKey masterKey = AzureMasterKey::parse(IDLParserContext("azureMasterKey"), keyId);
-
- HostAndPort keyVaultEndpoint = parseEndpoint(masterKey.getKeyVaultEndpoint());
-
- auto request = UniqueKmsRequest(
- kms_azure_request_wrapkey_new(keyVaultEndpoint.host().c_str(),
- bearerToken.toString().c_str(),
- masterKey.getKeyName().toString().c_str(),
- masterKey.getKeyVersion().value_or(""_sd).toString().c_str(),
- reinterpret_cast<const uint8_t*>(cdr.data()),
- cdr.length(),
- _config.opts.get()));
-
- size_t raw_len;
- auto raw_str = makeRequest<AzureDecryptResponse>(request.get(), keyVaultEndpoint, &raw_len);
-
- auto dataKey =
- kmsResponseToVector(StringData(reinterpret_cast<const char*>(raw_str.get()), raw_len));
-
- AzureMasterKeyAndMaterial keyAndMaterial;
- keyAndMaterial.setKeyMaterial(std::move(dataKey));
- keyAndMaterial.setMasterKey(std::move(masterKey));
-
- return keyAndMaterial.toBSON();
-}
-
-/**
- * Factory for AzureKMSService if user specifies azure config to mongo() JS constructor.
- */
-class AzureKMSServiceFactory final : public KMSServiceFactory {
-public:
- AzureKMSServiceFactory() = default;
- ~AzureKMSServiceFactory() = default;
-
- std::unique_ptr<KMSService> create(const BSONObj& config) final {
- auto field = config[KmsProviders::kAzureFieldName];
- if (field.eoo()) {
- return nullptr;
- }
-
- uassert(5265106,
- "Misconfigured Azure KMS Config: {}"_format(field.toString()),
- field.type() == BSONType::Object);
-
- auto obj = field.Obj();
- return AzureKMSService::create(AzureKMS::parse(IDLParserContext("root"), obj));
- }
-};
-
-} // namespace
-
-MONGO_INITIALIZER(KMSRegisterAzure)(::mongo::InitializerContext*) {
- kms_message_init();
- KMSServiceController::registerFactory(KMSProviderEnum::azure,
- std::make_unique<AzureKMSServiceFactory>());
-}
-
-} // namespace mongo
diff --git a/src/mongo/shell/kms_gcp.cpp b/src/mongo/shell/kms_gcp.cpp
deleted file mode 100644
index 81ec2737f7e..00000000000
--- a/src/mongo/shell/kms_gcp.cpp
+++ /dev/null
@@ -1,339 +0,0 @@
-/**
- * Copyright (C) 2021-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-
-#include "mongo/platform/basic.h"
-
-#include <fmt/format.h>
-#include <kms_message/kms_gcp_request.h>
-#include <kms_message/kms_message.h>
-
-#include "mongo/bson/json.h"
-#include "mongo/shell/kms.h"
-#include "mongo/shell/kms_network.h"
-#include "mongo/util/net/ssl_manager.h"
-#include "mongo/util/net/ssl_options.h"
-
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl
-
-
-namespace mongo {
-namespace {
-
-using namespace fmt::literals;
-
-constexpr StringData kGcpKms = "gcp"_sd;
-
-// Default endpoints for GCP
-constexpr StringData kDefaultOauthEndpoint = "oauth2.googleapis.com"_sd;
-constexpr StringData kDefaultOauthScope = "https://www.googleapis.com/auth/cloudkms"_sd;
-constexpr StringData kGcpKMSEndpoint = "https://cloudkms.googleapis.com:443"_sd;
-
-// Field names for BSON objects containing key vault information
-constexpr StringData kProjectIdField = "projectId"_sd;
-constexpr StringData kLocationIdField = "location"_sd;
-constexpr StringData kKeyRingField = "keyRing"_sd;
-constexpr StringData kKeyNameField = "keyName"_sd;
-constexpr StringData kKeyVerisionField = "keyVersion"_sd;
-
-/**
- * GCP configuration settings
- */
-struct GCPConfig {
- // E-mail address that will be used for GCP OAuth requests.
- std::string email;
-
- // PKCS#8 private key
- std::string privateKey;
-
- // Options to pass to GCP KMS requests
- UniqueKmsRequestOpts opts;
-};
-
-void uassertKmsRequestInternal(kms_request_t* request, bool ok) {
- if (!ok) {
- const char* msg = kms_request_get_error(request);
- uasserted(5265000, str::stream() << "Internal GCP KMS Error: " << msg);
- }
-}
-
-#define uassertKmsRequest(X) uassertKmsRequestInternal(request, (X))
-
-/**
- * Manages OAuth token requests and caching
- */
-class GCPKMSOAuthService final : public KMSOAuthService {
-public:
- GCPKMSOAuthService(const GCPConfig& config,
- HostAndPort endpoint,
- std::shared_ptr<SSLManagerInterface> sslManager)
- : KMSOAuthService(endpoint, sslManager), _config(config) {}
-
-protected:
- UniqueKmsRequest getOAuthRequest() {
- std::string audience = "https://{}/token"_format(_oAuthEndpoint.host());
- std::string scope;
- if (_oAuthEndpoint.host() != kDefaultOauthEndpoint.toString()) {
- scope = "https://www.{}/auth/cloudkms"_format(_oAuthEndpoint.toString());
- } else {
- scope = kDefaultOauthScope.toString();
- }
- uassert(5365009,
- str::stream() << "Internal GCP KMS Error: Private key not encoded in base64.",
- base64::validate(_config.privateKey));
- std::string privateKeyDecoded = base64::decode(_config.privateKey);
-
- auto request = UniqueKmsRequest(kms_gcp_request_oauth_new(_oAuthEndpoint.host().c_str(),
- _config.email.c_str(),
- audience.c_str(),
- scope.c_str(),
- privateKeyDecoded.c_str(),
- privateKeyDecoded.size(),
- _config.opts.get()));
-
- const char* msg = kms_request_get_error(request.get());
- uassert(5265003, str::stream() << "Internal GCP KMS Error: " << msg, msg == nullptr);
-
- return request;
- }
-
-private:
- const GCPConfig& _config;
-};
-
-/**
- * Manages SSL information and config for how to talk to GCP KMS.
- */
-class GCPKMSService final : public KMSService {
-public:
- GCPKMSService() = default;
-
- static std::unique_ptr<KMSService> create(const GcpKMS&);
-
-
- SecureVector<uint8_t> decrypt(ConstDataRange cdr, BSONObj masterKey) final;
-
- BSONObj encryptDataKeyByBSONObj(ConstDataRange cdr, BSONObj keyId) final;
-
- void configureOauthService(HostAndPort endpoint);
-
- StringData name() const {
- return kGcpKms;
- }
-
-private:
- std::vector<uint8_t> encrypt(ConstDataRange cdr, const BSONObj& kmsKeyId);
-
-private:
- // SSL Manager
- std::shared_ptr<SSLManagerInterface> _sslManager;
-
- // Server to connect to
- HostAndPort _server;
-
- // GCP configuration settings
- GCPConfig _config;
-
- // Service for managing oauth requests and token cache
- std::unique_ptr<GCPKMSOAuthService> _oauthService;
-};
-
-std::vector<uint8_t> GCPKMSService::encrypt(ConstDataRange cdr, const BSONObj& kmsKeyId) {
- StringData bearerToken = _oauthService->getBearerToken();
- GcpMasterKey masterKey = GcpMasterKey::parse(IDLParserContext("gcpMasterKey"), kmsKeyId);
-
- auto request = UniqueKmsRequest(kms_gcp_request_encrypt_new(
- _server.host().c_str(),
- bearerToken.toString().c_str(),
- masterKey.getProjectId().toString().c_str(),
- masterKey.getLocation().toString().c_str(),
- masterKey.getKeyRing().toString().c_str(),
- masterKey.getKeyName().toString().c_str(),
- masterKey.getKeyVersion().has_value() ? masterKey.getKeyVersion().value().toString().c_str()
- : nullptr,
- reinterpret_cast<const uint8_t*>(cdr.data()),
- cdr.length(),
- _config.opts.get()));
-
- auto buffer = UniqueKmsCharBuffer(kms_request_to_string(request.get()));
- auto buffer_len = strlen(buffer.get());
-
- KMSNetworkConnection connection(_sslManager.get());
- auto response = connection.makeOneRequest(_server, ConstDataRange(buffer.get(), buffer_len));
-
- auto body = kms_response_get_body(response.get(), nullptr);
-
- BSONObj obj = fromjson(body);
-
- if (obj.hasField("error")) {
- GcpKMSError gcpResponse;
- try {
- gcpResponse =
- GcpKMSError::parse(IDLParserContext("gcpEncryptError"), obj["error"].Obj());
- } catch (DBException& dbe) {
- uasserted(5265005,
- str::stream() << "GCP KMS failed to parse error message: " << dbe.toString()
- << ", Response : " << obj);
- }
-
- uasserted(5256006,
- str::stream() << "GCP KMS failed to encrypt: " << gcpResponse.getCode() << " "
- << gcpResponse.getStatus() << " : " << gcpResponse.getMessage());
- }
-
- auto gcpResponce = GcpEncryptResponse::parse(IDLParserContext("gcpEncryptResponse"), obj);
-
- auto blobStr = base64::decode(gcpResponce.getCiphertext());
-
- return kmsResponseToVector(blobStr);
-}
-
-SecureVector<uint8_t> GCPKMSService::decrypt(ConstDataRange cdr, BSONObj masterKey) {
- auto gcpMasterKey = GcpMasterKey::parse(IDLParserContext("gcpMasterKey"), masterKey);
- StringData bearerToken = _oauthService->getBearerToken();
-
- auto request =
- UniqueKmsRequest(kms_gcp_request_decrypt_new(_server.host().c_str(),
- bearerToken.toString().c_str(),
- gcpMasterKey.getProjectId().toString().c_str(),
- gcpMasterKey.getLocation().toString().c_str(),
- gcpMasterKey.getKeyRing().toString().c_str(),
- gcpMasterKey.getKeyName().toString().c_str(),
- reinterpret_cast<const uint8_t*>(cdr.data()),
- cdr.length(),
- _config.opts.get()));
-
- auto buffer = UniqueKmsCharBuffer(kms_request_to_string(request.get()));
- auto buffer_len = strlen(buffer.get());
- KMSNetworkConnection connection(_sslManager.get());
- auto response = connection.makeOneRequest(_server, ConstDataRange(buffer.get(), buffer_len));
-
- auto body = kms_response_get_body(response.get(), nullptr);
-
- BSONObj obj = fromjson(body);
-
- if (obj.hasField("error")) {
- GcpKMSError gcpResponse;
- try {
- gcpResponse =
- GcpKMSError::parse(IDLParserContext("gcpDecryptError"), obj["error"].Obj());
- } catch (DBException& dbe) {
- uasserted(5265007,
- str::stream() << "GCP KMS failed to parse error message: " << dbe.toString()
- << ", Response : " << obj);
- }
-
- uasserted(5256008,
- str::stream() << "GCP KMS failed to decrypt: " << gcpResponse.getCode() << " "
- << gcpResponse.getStatus() << " : " << gcpResponse.getMessage());
- }
-
- auto gcpResponce = GcpDecryptResponse::parse(IDLParserContext("gcpDecryptResponse"), obj);
-
- auto blobStr = base64::decode(gcpResponce.getPlaintext());
-
- return kmsResponseToSecureVector(blobStr);
-}
-
-BSONObj GCPKMSService::encryptDataKeyByBSONObj(ConstDataRange cdr, BSONObj keyId) {
- auto dataKey = encrypt(cdr, keyId);
-
- GcpMasterKey masterKey = GcpMasterKey::parse(IDLParserContext("gcpMasterKey"), keyId);
-
- GcpMasterKeyAndMaterial keyAndMaterial;
- keyAndMaterial.setKeyMaterial(std::move(dataKey));
- keyAndMaterial.setMasterKey(std::move(masterKey));
-
- return keyAndMaterial.toBSON();
-}
-
-std::unique_ptr<KMSService> GCPKMSService::create(const GcpKMS& config) {
- auto gcpKMS = std::make_unique<GCPKMSService>();
-
- SSLParams params;
- getSSLParamsForNetworkKMS(&params);
-
- HostAndPort oauthHostAndPort(kDefaultOauthEndpoint.toString(), 443);
- if (config.getEndpoint().has_value()) {
- // Leave the CA file empty so we default to system CA but for local testing allow it to
- // inherit the CA file.
- params.sslCAFile = sslGlobalParams.sslCAFile;
- oauthHostAndPort = parseUrl(config.getEndpoint().value());
- }
-
- gcpKMS->_sslManager = SSLManagerInterface::create(params, false);
-
- gcpKMS->configureOauthService(oauthHostAndPort);
-
- gcpKMS->_server = parseUrl(config.getEndpoint().value_or(kGcpKMSEndpoint));
-
- gcpKMS->_config.email = config.getEmail().toString();
-
- gcpKMS->_config.opts = UniqueKmsRequestOpts(kms_request_opt_new());
- kms_request_opt_set_provider(gcpKMS->_config.opts.get(), KMS_REQUEST_PROVIDER_GCP);
-
- gcpKMS->_config.privateKey = config.getPrivateKey().toString();
-
- return gcpKMS;
-}
-
-void GCPKMSService::configureOauthService(HostAndPort endpoint) {
- _oauthService = std::make_unique<GCPKMSOAuthService>(_config, endpoint, _sslManager);
-}
-
-/**
- * Factory for GCPKMSService if user specifies gcp config to mongo() JS constructor.
- */
-class GCPKMSServiceFactory final : public KMSServiceFactory {
-public:
- GCPKMSServiceFactory() = default;
- ~GCPKMSServiceFactory() = default;
-
- std::unique_ptr<KMSService> create(const BSONObj& config) final {
- auto field = config[KmsProviders::kGcpFieldName];
- if (field.eoo()) {
- return nullptr;
- }
- uassert(5265009,
- "Misconfigured GCP KMS Config: {}"_format(field.toString()),
- field.type() == BSONType::Object);
- auto obj = field.Obj();
- return GCPKMSService::create(GcpKMS::parse(IDLParserContext("root"), obj));
- }
-};
-
-} // namespace
-
-MONGO_INITIALIZER(KMSRegisterGCP)(::mongo::InitializerContext*) {
- kms_message_init();
- KMSServiceController::registerFactory(KMSProviderEnum::gcp,
- std::make_unique<GCPKMSServiceFactory>());
-}
-
-} // namespace mongo
diff --git a/src/mongo/shell/kms_local.cpp b/src/mongo/shell/kms_local.cpp
index f67230ed45f..085fe4328e1 100644
--- a/src/mongo/shell/kms_local.cpp
+++ b/src/mongo/shell/kms_local.cpp
@@ -27,8 +27,6 @@
* it in the license file.
*/
-#include <kms_message/kms_message.h>
-
#include <stdlib.h>
#include "mongo/base/init.h"
@@ -64,6 +62,10 @@ public:
BSONObj encryptDataKeyByString(ConstDataRange cdr, StringData keyId) final;
+ SymmetricKey& getMasterKey() final {
+ return _key;
+ }
+
private:
std::vector<uint8_t> encrypt(ConstDataRange cdr, StringData kmsKeyId);
diff --git a/src/mongo/shell/kms_network.cpp b/src/mongo/shell/kms_network.cpp
deleted file mode 100644
index 686b66ceaeb..00000000000
--- a/src/mongo/shell/kms_network.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/**
- * Copyright (C) 2020-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/shell/kms_network.h"
-
-#include "mongo/bson/json.h"
-#include "mongo/shell/kms.h"
-#include "mongo/shell/kms_gen.h"
-#include "mongo/util/text.h"
-
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kControl
-
-
-namespace mongo {
-
-void KMSNetworkConnection::connect(const HostAndPort& host) {
- auto makeAddress = [](const auto& host) -> SockAddr {
- try {
- return SockAddr::create(host.host().c_str(), host.port(), AF_UNSPEC);
- } catch (const DBException& ex) {
- uasserted(51136, "Unable to resolve KMS server address" + causedBy(ex));
- }
-
- MONGO_UNREACHABLE;
- };
-
- auto addr = makeAddress(host);
-
- size_t attempt = 0;
- constexpr size_t kMaxAttempts = 20;
- while (!_socket->connect(addr)) {
- ++attempt;
- if (attempt > kMaxAttempts) {
- uasserted(51137,
- str::stream() << "Could not connect to KMS server " << addr.toString());
- }
- }
-
- if (!_socket->secure(_sslManager, host.host())) {
- uasserted(51138,
- str::stream() << "Failed to perform SSL handshake with the KMS server "
- << addr.toString());
- }
-}
-
-// Sends a request message to the KMS server and creates a KMS Response.
-UniqueKmsResponse KMSNetworkConnection::sendRequest(ConstDataRange request) {
- std::array<char, 512> resp;
-
- _socket->send(reinterpret_cast<const char*>(request.data()), request.length(), "KMS request");
-
- auto parser = UniqueKmsResponseParser(kms_response_parser_new());
- int bytes_to_read = 0;
-
- while ((bytes_to_read = kms_response_parser_wants_bytes(parser.get(), resp.size())) > 0) {
- bytes_to_read = std::min(bytes_to_read, static_cast<int>(resp.size()));
- bytes_to_read = _socket->unsafe_recv(resp.data(), bytes_to_read);
-
- uassert(51139,
- "kms_response_parser_feed failed",
- kms_response_parser_feed(
- parser.get(), reinterpret_cast<uint8_t*>(resp.data()), bytes_to_read));
- }
-
- auto response = UniqueKmsResponse(kms_response_parser_get_response(parser.get()));
-
- return response;
-}
-
-UniqueKmsResponse KMSNetworkConnection::makeOneRequest(const HostAndPort& host,
- ConstDataRange request) {
- connect(host);
-
- auto resp = sendRequest(request);
-
- _socket->close();
-
- return resp;
-}
-
-void getSSLParamsForNetworkKMS(SSLParams* params) {
- params->sslPEMKeyFile = "";
- params->sslPEMKeyPassword = "";
- params->sslClusterFile = "";
- params->sslClusterPassword = "";
- params->sslCAFile = "";
-
- params->sslCRLFile = "";
-
- // Copy the rest from the global SSL manager options.
- params->sslFIPSMode = sslGlobalParams.sslFIPSMode;
-
- // KMS servers never should have invalid certificates
- params->sslAllowInvalidCertificates = false;
- params->sslAllowInvalidHostnames = false;
-
- params->sslDisabledProtocols =
- std::vector({SSLParams::Protocols::TLS1_0, SSLParams::Protocols::TLS1_1});
-}
-
-std::vector<uint8_t> kmsResponseToVector(StringData str) {
- std::vector<uint8_t> blob;
-
- std::transform(std::begin(str), std::end(str), std::back_inserter(blob), [](auto c) {
- return static_cast<uint8_t>(c);
- });
-
- return blob;
-}
-
-SecureVector<uint8_t> kmsResponseToSecureVector(StringData str) {
- SecureVector<uint8_t> blob(str.size());
-
- std::transform(std::begin(str), std::end(str), blob->data(), [](auto c) {
- return static_cast<uint8_t>(c);
- });
-
- return blob;
-}
-
-StringData KMSOAuthService::getBearerToken() {
-
- if (!_cachedToken.empty() && _expirationDateTime > Date_t::now()) {
- return _cachedToken;
- }
-
- makeBearerTokenRequest();
-
- return _cachedToken;
-}
-
-void KMSOAuthService::makeBearerTokenRequest() {
- UniqueKmsRequest request = getOAuthRequest();
-
- auto buffer = UniqueKmsCharBuffer(kms_request_to_string(request.get()));
- auto buffer_len = strlen(buffer.get());
-
- KMSNetworkConnection connection(_sslManager.get());
- auto response =
- connection.makeOneRequest(_oAuthEndpoint, ConstDataRange(buffer.get(), buffer_len));
-
- auto body = kms_response_get_body(response.get(), nullptr);
-
- BSONObj obj = fromjson(body);
-
- auto field = obj[OAuthErrorResponse::kErrorFieldName];
-
- if (!field.eoo()) {
- OAuthErrorResponse oAuthErrorResponse;
- try {
- oAuthErrorResponse = OAuthErrorResponse::parse(IDLParserContext("oauthError"), obj);
- } catch (DBException& dbe) {
- uasserted(ErrorCodes::FailedToParse,
- str::stream() << "Failed to parse error message: " << dbe.toString()
- << ", Response : " << obj);
- }
-
- std::string description;
- if (oAuthErrorResponse.getError_description().has_value()) {
- description = str::stream()
- << " : " << oAuthErrorResponse.getError_description().value().toString();
- }
- uasserted(ErrorCodes::OperationFailed,
- str::stream() << "Failed to make oauth request: " << oAuthErrorResponse.getError()
- << description);
- }
-
- auto kmsResponse = OAuthResponse::parse(IDLParserContext("OAuthResponse"), obj);
-
- _cachedToken = kmsResponse.getAccess_token().toString();
-
- // Offset the expiration time by a the socket timeout as proxy for round-trip time to the OAuth
- // server. This approximation will compute the expiration time a litte earlier then needed but
- // will ensure that it uses a stale bearer token.
- Seconds requestBufferTime = 2 * Seconds((int)KMSNetworkConnection::so_timeout_seconds);
-
- // expires_in is optional but Azure and GCP always return it but to be safe, we pick a default
- _expirationDateTime =
- Date_t::now() + Seconds(kmsResponse.getExpires_in().value_or(60)) - requestBufferTime;
-}
-
-} // namespace mongo
diff --git a/src/mongo/shell/kms_network.h b/src/mongo/shell/kms_network.h
deleted file mode 100644
index 724412f869b..00000000000
--- a/src/mongo/shell/kms_network.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * Copyright (C) 2020-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#include <string>
-
-#include "mongo/util/kms_message_support.h"
-#include "mongo/util/net/sock.h"
-#include "mongo/util/net/ssl_manager.h"
-#include "mongo/util/net/ssl_options.h"
-#include "mongo/util/time_support.h"
-
-namespace mongo {
-
-/**
- * Make a request to an HTTP endpoint.
- *
- * Does not maintain a persistent HTTP connection.
- */
-class KMSNetworkConnection {
-public:
- static constexpr double so_timeout_seconds = 10;
-
- KMSNetworkConnection(SSLManagerInterface* ssl)
- : _sslManager(ssl),
- _socket(std::make_unique<Socket>(so_timeout_seconds, logv2::LogSeverity::Info())) {}
-
- UniqueKmsResponse makeOneRequest(const HostAndPort& host, ConstDataRange request);
-
-private:
- UniqueKmsResponse sendRequest(ConstDataRange request);
-
- void connect(const HostAndPort& host);
-
-private:
- // SSL Manager for connections
- SSLManagerInterface* _sslManager;
-
- // Synchronous socket
- std::unique_ptr<Socket> _socket;
-};
-
-/**
- * Creates an initial SSLParams object for KMS over the network.
- */
-void getSSLParamsForNetworkKMS(SSLParams*);
-
-/**
- * Converts a base64 encoded KMS response to a vector of bytes.
- */
-std::vector<uint8_t> kmsResponseToVector(StringData str);
-
-/**
- * Converts a base64 encoded KMS response to a securely allocated vector of bytes.
- */
-SecureVector<uint8_t> kmsResponseToSecureVector(StringData str);
-
-/**
- * Base class for KMS services that use OAuth for authorization.
- *
- * Each service only talks to one OAuth endpoint so caching bearer tokens is simple.
- */
-class KMSOAuthService {
-public:
- KMSOAuthService(HostAndPort oAuthEndpoint, std::shared_ptr<SSLManagerInterface> sslManager)
- : _oAuthEndpoint(oAuthEndpoint), _sslManager(sslManager) {}
-
- /**
- * Get a bearer token to use to make requests. It may be cached.
- */
- StringData getBearerToken();
-
-protected:
- /**
- * Construct a valid kms request for retrieving a new OAuth Bearer token
- */
- virtual UniqueKmsRequest getOAuthRequest() = 0;
-
-protected:
- // OAuth Service endpoint
- HostAndPort _oAuthEndpoint;
-
-private:
- /**
- * Make a TLS request to a service to fetch a bearer token.
- */
- void makeBearerTokenRequest();
-
-private:
- // SSL Manager
- std::shared_ptr<SSLManagerInterface> _sslManager;
-
- // Cached access token
- std::string _cachedToken;
-
- // Expiration datetime of access token
- Date_t _expirationDateTime;
-};
-
-} // namespace mongo