THRIFT-4084: Add a SSL/TLS negotiation check to crossfeature to verify SSLv3 is not active and that at least one of TLSv1.0 through 1.2 are accepted.
Client: csharp, d, go, nodejs, perl
This closes #1197
diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp
index da20b89..a918bfb 100644
--- a/test/cpp/src/TestClient.cpp
+++ b/test/cpp/src/TestClient.cpp
@@ -136,8 +136,11 @@
int ERR_EXCEPTIONS = 8;
int ERR_UNKNOWN = 64;
- string testDir = boost::filesystem::system_complete(argv[0]).parent_path().parent_path().parent_path().string();
- string pemPath = testDir + "/keys/CA.pem";
+ string testDir = boost::filesystem::system_complete(argv[0]).parent_path().parent_path().parent_path().string();
+ string caPath = testDir + "/keys/CA.pem";
+ string certPath = testDir + "/keys/client.crt";
+ string keyPath = testDir + "/keys/client.key";
+
#if _WIN32
transport::TWinsockSingleton::create();
#endif
@@ -232,9 +235,15 @@
boost::shared_ptr<TSSLSocketFactory> factory;
if (ssl) {
+ cout << "Client Certificate File: " << certPath << endl;
+ cout << "Client Key File: " << keyPath << endl;
+ cout << "CA File: " << caPath << endl;
+
factory = boost::shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
factory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
- factory->loadTrustedCertificates(pemPath.c_str());
+ factory->loadTrustedCertificates(caPath.c_str());
+ factory->loadCertificate(certPath.c_str());
+ factory->loadPrivateKey(keyPath.c_str());
factory->authenticate(true);
socket = factory->createSocket(host, port);
} else {
diff --git a/test/features/Makefile.am b/test/features/Makefile.am
index f8d6538..337d789 100644
--- a/test/features/Makefile.am
+++ b/test/features/Makefile.am
@@ -21,8 +21,10 @@
index.html \
known_failures_Linux.json \
Makefile.am \
+ nosslv3.sh \
string_limit.py \
tests.json \
theader_binary.py \
setup.cfg \
+ tls.sh \
util.py
diff --git a/test/features/nosslv3.sh b/test/features/nosslv3.sh
new file mode 100755
index 0000000..e550d51
--- /dev/null
+++ b/test/features/nosslv3.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+#
+# Checks to make sure SSLv3 is not allowed by a server.
+#
+
+THRIFTHOST=localhost
+THRIFTPORT=9090
+
+while [[ $# -ge 1 ]]; do
+ arg="$1"
+ argIN=(${arg//=/ })
+
+ case ${argIN[0]} in
+ -h|--host)
+ THRIFTHOST=${argIN[1]}
+ shift # past argument
+ ;;
+ -p|--port)
+ THRIFTPORT=${argIN[1]}
+ shift # past argument
+ ;;
+ *)
+ # unknown option ignored
+ ;;
+ esac
+
+ shift # past argument or value
+done
+
+function nosslv3
+{
+ local nego
+ local negodenied
+
+ # echo "openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -ssl3 2>&1 < /dev/null"
+ nego=$(openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -ssl3 2>&1 < /dev/null)
+ negodenied=$?
+
+ if [[ $negodenied -ne 0 ]]; then
+ echo "[pass] SSLv3 negotiation disabled"
+ echo $nego
+ return 0
+ fi
+
+ echo "[fail] SSLv3 negotiation enabled! stdout:"
+ echo $nego
+ return 1
+}
+
+nosslv3
+exit $?
diff --git a/test/features/tests.json b/test/features/tests.json
index cfcb4b6..3ab3b68 100644
--- a/test/features/tests.json
+++ b/test/features/tests.json
@@ -90,5 +90,27 @@
"transports": ["buffered"],
"sockets": ["ip"],
"workdir": "features"
+ },
+ {
+ "name": "nosslv3",
+ "comment": "check to make sure SSLv3 is not supported",
+ "command": [
+ "nosslv3.sh"
+ ],
+ "protocols": ["binary"],
+ "transports": ["buffered"],
+ "sockets": ["ip-ssl"],
+ "workdir": "features"
+ },
+ {
+ "name": "tls",
+ "comment": "check to make sure TLSv1.0 or later is supported",
+ "command": [
+ "tls.sh"
+ ],
+ "protocols": ["binary"],
+ "transports": ["buffered"],
+ "sockets": ["ip-ssl"],
+ "workdir": "features"
}
]
diff --git a/test/features/tls.sh b/test/features/tls.sh
new file mode 100755
index 0000000..dada6ab
--- /dev/null
+++ b/test/features/tls.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+#
+# Checks to make sure TLSv1.0 or later is allowed by a server.
+#
+
+THRIFTHOST=localhost
+THRIFTPORT=9090
+
+while [[ $# -ge 1 ]]; do
+ arg="$1"
+ argIN=(${arg//=/ })
+
+ case ${argIN[0]} in
+ -h|--host)
+ THRIFTHOST=${argIN[1]}
+ shift # past argument
+ ;;
+ -p|--port)
+ THRIFTPORT=${argIN[1]}
+ shift # past argument
+ ;;
+ *)
+ # unknown option ignored
+ ;;
+ esac
+
+ shift # past argument or value
+done
+
+declare -A EXPECT_NEGOTIATE
+EXPECT_NEGOTIATE[tls1]=1
+EXPECT_NEGOTIATE[tls1_1]=1
+EXPECT_NEGOTIATE[tls1_2]=1
+
+failures=0
+
+function tls
+{
+ for PROTO in "${!EXPECT_NEGOTIATE[@]}"; do
+
+ local nego
+ local negodenied
+ local res
+
+ echo "openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -$PROTO 2>&1 < /dev/null"
+ nego=$(openssl s_client -connect $THRIFTHOST:$THRIFTPORT -CAfile ../keys/CA.pem -$PROTO 2>&1 < /dev/null)
+ negodenied=$?
+ echo "result of command: $negodenied"
+
+ res="enabled"; if [[ ${EXPECT_NEGOTIATE[$PROTO]} -eq 0 ]]; then res="disabled"; fi
+
+ if [[ $negodenied -ne ${EXPECT_NEGOTIATE[$PROTO]} ]]; then
+ echo "$PROTO negotiation allowed"
+ else
+ echo "[warn] $PROTO negotiation did not work"
+ echo $nego
+ ((failures++))
+ fi
+ done
+}
+
+tls
+
+if [[ $failures -eq 3 ]]; then
+ echo "[fail] At least one of TLSv1.0, TLSv1.1, or TLSv1.2 needs to work, but does not"
+ exit $failures
+fi
+
+echo "[pass] At least one of TLSv1.0, TLSv1.1, or TLSv1.2 worked"
+exit 0
diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json
index d60997d..5ca6d4e 100644
--- a/test/known_failures_Linux.json
+++ b/test/known_failures_Linux.json
@@ -47,6 +47,9 @@
"csharp-d_binary_buffered-ip-ssl",
"csharp-d_compact_buffered-ip-ssl",
"csharp-d_json_buffered-ip-ssl",
+ "csharp-d_binary_framed-ip-ssl",
+ "csharp-d_compact_framed-ip-ssl",
+ "csharp-d_json_framed-ip-ssl",
"csharp-erl_binary_buffered-ip-ssl",
"csharp-erl_binary_framed-ip-ssl",
"csharp-erl_compact_buffered-ip-ssl",
@@ -105,6 +108,7 @@
"d-cpp_json_http-ip-ssl",
"d-d_binary_http-ip",
"d-d_compact_http-ip",
+ "d-d_json_http-ip",
"d-dart_binary_framed-ip",
"d-dart_binary_http-ip",
"d-dart_compact_framed-ip",
@@ -220,9 +224,5 @@
"hs-py3_json_framed-ip",
"java-d_compact_buffered-ip",
"java-d_compact_buffered-ip-ssl",
- "java-d_compact_framed-ip",
- "perl-erl_binary_buffered-ip-ssl",
- "perl-erl_binary_framed-ip-ssl",
- "perl-perl_binary_buffered-ip-ssl",
- "perl-perl_binary_framed-ip-ssl"
+ "java-d_compact_framed-ip"
]
diff --git a/test/tests.json b/test/tests.json
index e228928..f1d6a47 100644
--- a/test/tests.json
+++ b/test/tests.json
@@ -121,8 +121,8 @@
"framed:fastframed"
],
"sockets": [
- "ip-ssl",
- "ip"
+ "ip",
+ "ip-ssl"
],
"protocols": [
"compact",
@@ -415,7 +415,7 @@
"-I../../lib/perl/lib/",
"TestClient.pl",
"--ca=../keys/CA.pem",
- "--cert=../keys/client.pem",
+ "--cert=../keys/client.crt",
"--key=../keys/client.key"
]
},
@@ -425,8 +425,7 @@
"-Igen-perl/",
"-I../../lib/perl/lib/",
"TestServer.pl",
- "--ca=../keys/CA.pem",
- "--cert=../keys/server.pem",
+ "--cert=../keys/server.crt",
"--key=../keys/server.key"
]
},