diff options
author | Shreyas Kalyan <shreyaskalyan@gmail.com> | 2018-09-25 16:15:24 -0400 |
---|---|---|
committer | Shreyas Kalyan <shreyaskalyan@gmail.com> | 2018-10-08 11:36:20 -0400 |
commit | 0169d181bd15057a57616af55838b9e132133dd6 (patch) | |
tree | 0f4bc335d8df94389619a840c0f2ca0f46a0a674 /jstests/ssl | |
parent | 82a07e2f04f47de1602885ba00ecbca0ee72fc3f (diff) | |
download | mongo-0169d181bd15057a57616af55838b9e132133dd6.tar.gz |
SERVER-36618 Write JS integration tests that validate whichever TLS suites are available on each Evergreen platform
Diffstat (limited to 'jstests/ssl')
-rw-r--r-- | jstests/ssl/ssl_ECDHE_suites.js | 93 | ||||
-rw-r--r-- | jstests/ssl/sslyze_tester.py | 52 |
2 files changed, 145 insertions, 0 deletions
diff --git a/jstests/ssl/ssl_ECDHE_suites.js b/jstests/ssl/ssl_ECDHE_suites.js new file mode 100644 index 00000000000..ebcaa6fc7a3 --- /dev/null +++ b/jstests/ssl/ssl_ECDHE_suites.js @@ -0,0 +1,93 @@ +// Test that a client can authenicate against the server with roles. +// Also validates RFC2253 +load('jstests/ssl/libs/ssl_helpers.js'); + +(function() { + "use strict"; + + if (getBuildInfo().buildEnvironment.target_os === "macOS") { + return; + } + + const suites = [ + "SSLV2 Cipher Suites", + "SSLV3 Cipher Suites", + "TLSV1_0 Cipher Suites", + "TLSV1_1 Cipher Suites", + "TLSV1_2 Cipher Suites", + "TLSV1_3 Cipher Suites" + ]; + const SERVER_CERT = "jstests/libs/server.pem"; + + function runSSLYze(port) { + let python = "/usr/bin/env python3"; + let sslyze = " jstests/ssl/sslyze_tester.py "; + + if (_isWindows()) { + const paths = ["c:\\python36\\python.exe", "c:\\python\\python36\\python.exe"]; + for (let p of paths) { + if (fileExists(p)) { + python = p; + } + } + } + + const python_command = python + sslyze + "--port=" + port; + let ret = 0; + if (_isWindows()) { + ret = runProgram('cmd.exe', '/c', python_command); + } else { + ret = runProgram('/bin/sh', '-c', python_command); + } + assert.eq(ret, 0); + + try { + let ciphers = cat("jstests/ssl/ciphers.json"); + let cipherDict = JSON.parse(ciphers); + return cipherDict; + } catch (e) { + jsTestLog("Failed to parse: " + ciphers + "\n" + ciphers); + throw e; + } finally { + const python_delete_command = python + sslyze + "--delete"; + if (_isWindows()) { + ret = runProgram('cmd.exe', '/c', python_delete_command); + } else { + ret = runProgram('/bin/sh', '-c', python_delete_command); + } + assert.eq(ret, 0); + } + } + + function testSSLYzeOutput(cipherDict) { + // Checking that SSL 1.0, 2.0, 3.0 and TLS 1.0 are not accepted + for (var i = 0; i < 3; i++) { + assert.eq(cipherDict[suites[i]].length, 0); + } + + // Printing TLS 1.1, 1.2, and 1.3 suites that are accepted + for (var i = 3; i < 6; i++) { + const TLSVersion = cipherDict[suites[i]].toString().split(","); + print('*************************\n' + suites[i] + ": "); + for (var j = 0; j < TLSVersion.length; j++) { + print(TLSVersion[j]); + } + } + } + + print("1. Testing x.509 auth to mongod"); + { + const x509_options = { + sslMode: "requireSSL", + sslCAFile: CA_CERT, + sslPEMKeyFile: SERVER_CERT, + ipv6: "", + bind_ip_all: "" + }; + let mongod = MongoRunner.runMongod(x509_options); + var cipherDict = runSSLYze(mongod.port); + testSSLYzeOutput(cipherDict); + + MongoRunner.stopMongod(mongod); + } +}());
\ No newline at end of file diff --git a/jstests/ssl/sslyze_tester.py b/jstests/ssl/sslyze_tester.py new file mode 100644 index 00000000000..70dda5f8c62 --- /dev/null +++ b/jstests/ssl/sslyze_tester.py @@ -0,0 +1,52 @@ +#! /usr/bin/env python3 + +# This is a wrapper file around the SSLYze package +# The SSLYze package is used for testing the TLS/SSL +# suites that we allow for connections. +import os, logging, json, argparse, urllib.parse +from sslyze.synchronous_scanner import SynchronousScanner +from sslyze.plugins import openssl_cipher_suites_plugin +from sslyze.plugins.openssl_cipher_suites_plugin import * +from sslyze.server_connectivity_tester import ServerConnectivityTester, ServerConnectivityError + +path = str(os.path.dirname(os.path.abspath(__file__))) +filename = f'{path}/ciphers.json' + +def server_scanner(p): + try: + logger = logging.getLogger(__name__) + logger.info("Opening file") + server_tester = ServerConnectivityTester( + hostname = 'localhost', + port=p + ) + server_info = server_tester.perform() + scanner = SynchronousScanner() + + results = dict() + suite_names = ['SSLV2 Cipher Suites', 'SSLV3 Cipher Suites', 'TLSV1_0 Cipher Suites', 'TLSV1_1 Cipher Suites', 'TLSV1_2 Cipher Suites', 'TLSV1_3 Cipher Suites'] + suites = [Sslv20ScanCommand, Sslv30ScanCommand, Tlsv10ScanCommand, Tlsv11ScanCommand, Tlsv12ScanCommand, Tlsv13ScanCommand] + + logger.info("Scanning SSL/TLS suites, writing to ciphers.json") + for suite_name, suite in zip(suite_names, suites): + scan = scanner.run_scan_command(server_info, suite()) + results[suite_name] = [cipher.name for cipher in scan.accepted_cipher_list] + + with open(filename, 'w') as outfile: + json.dump(results, outfile) + + except ServerConnectivityError as e: + raise RuntimeError(f'Could not connect to {e.server_info.hostname}: {e.error_message}') + +def main(): + parser = argparse.ArgumentParser(description='MongoDB SSL/TLS Suite Validation.') + parser.add_argument('-p', '--port', type=int, default=27017, help="Port to listen on") + parser.add_argument('-d', '--delete', action='store_true', help="Delete the ciphers.json file") + args = parser.parse_args() + if args.delete: + os.remove(filename) + else: + return server_scanner(args.port) + +if __name__ == '__main__': + main() |