summaryrefslogtreecommitdiff
path: root/jstests/ssl
diff options
context:
space:
mode:
authorShreyas Kalyan <shreyaskalyan@gmail.com>2018-09-25 16:15:24 -0400
committerShreyas Kalyan <shreyaskalyan@gmail.com>2018-10-08 11:36:20 -0400
commit0169d181bd15057a57616af55838b9e132133dd6 (patch)
tree0f4bc335d8df94389619a840c0f2ca0f46a0a674 /jstests/ssl
parent82a07e2f04f47de1602885ba00ecbca0ee72fc3f (diff)
downloadmongo-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.js93
-rw-r--r--jstests/ssl/sslyze_tester.py52
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()