diff options
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/client_encrypt/fle_auto_decrypt.js | 1 | ||||
-rw-r--r-- | jstests/client_encrypt/fle_aws_faults.js | 164 | ||||
-rw-r--r-- | jstests/client_encrypt/fle_azure_faults.js | 175 | ||||
-rw-r--r-- | jstests/client_encrypt/fle_encrypt_decrypt_shell.js | 14 | ||||
-rw-r--r-- | jstests/client_encrypt/fle_gcp_faults.js | 190 | ||||
-rw-r--r-- | jstests/client_encrypt/fle_key_faults.js | 14 | ||||
-rw-r--r-- | jstests/client_encrypt/fle_keys.js | 27 | ||||
-rw-r--r-- | jstests/client_encrypt/fle_valid_fle_options.js | 17 | ||||
-rw-r--r-- | jstests/client_encrypt/lib/fle_command_line_explicit_encryption.js | 8 | ||||
-rw-r--r-- | jstests/client_encrypt/lib/kms_http_common.py | 148 | ||||
-rw-r--r-- | jstests/client_encrypt/lib/kms_http_control.py | 52 | ||||
-rwxr-xr-x | jstests/client_encrypt/lib/kms_http_server.py | 244 | ||||
-rwxr-xr-x | jstests/client_encrypt/lib/kms_http_server_azure.py | 239 | ||||
-rwxr-xr-x | jstests/client_encrypt/lib/kms_http_server_gcp.py | 240 | ||||
-rw-r--r-- | jstests/client_encrypt/lib/mock_kms.js | 188 |
15 files changed, 20 insertions, 1701 deletions
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"; - } -} |