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/lib/csharp/src/Transport/TTLSServerSocket.cs b/lib/csharp/src/Transport/TTLSServerSocket.cs
index 86a4494..d51c217 100644
--- a/lib/csharp/src/Transport/TTLSServerSocket.cs
+++ b/lib/csharp/src/Transport/TTLSServerSocket.cs
@@ -108,7 +108,7 @@
             X509Certificate2 certificate,
             RemoteCertificateValidationCallback clientCertValidator = null,
             LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
-            // TODO: Enable Tls1 and Tls2 (TLS 1.1 and 1.2) by default once we start using .NET 4.5+.
+            // TODO: Enable Tls11 and Tls12 (TLS 1.1 and 1.2) by default once we start using .NET 4.5+.
             SslProtocols sslProtocols = SslProtocols.Tls)
         {
             if (!certificate.HasPrivateKey)
@@ -126,7 +126,7 @@
             try
             {
                 // Create server socket
-				this.server = TSocketVersionizer.CreateTcpListener(port);
+                this.server = TSocketVersionizer.CreateTcpListener(port);
                 this.server.Server.NoDelay = true;
             }
             catch (Exception)
diff --git a/lib/d/src/thrift/transport/ssl.d b/lib/d/src/thrift/transport/ssl.d
index a78a2ed..fbcb6ee 100644
--- a/lib/d/src/thrift/transport/ssl.d
+++ b/lib/d/src/thrift/transport/ssl.d
@@ -249,7 +249,9 @@
     }
     count_++;
 
-    ctx_ = SSL_CTX_new(TLSv1_method());
+    ctx_ = SSL_CTX_new(SSLv23_method());
+    SSL_CTX_set_options(ctx_, SSL_OP_NO_SSLv2);
+    SSL_CTX_set_options(ctx_, SSL_OP_NO_SSLv3);   // THRIFT-3164
     enforce(ctx_, getSSLException("SSL_CTX_new"));
     SSL_CTX_set_mode(ctx_, SSL_MODE_AUTO_RETRY);
   }
diff --git a/lib/go/thrift/ssl_server_socket.go b/lib/go/thrift/ssl_server_socket.go
index 58f859b..907afca 100644
--- a/lib/go/thrift/ssl_server_socket.go
+++ b/lib/go/thrift/ssl_server_socket.go
@@ -20,9 +20,9 @@
 package thrift
 
 import (
+	"crypto/tls"
 	"net"
 	"time"
-	"crypto/tls"
 )
 
 type TSSLServerSocket struct {
@@ -38,6 +38,9 @@
 }
 
 func NewTSSLServerSocketTimeout(listenAddr string, cfg *tls.Config, clientTimeout time.Duration) (*TSSLServerSocket, error) {
+	if cfg.MinVersion == 0 {
+		cfg.MinVersion = tls.VersionTLS10
+	}
 	addr, err := net.ResolveTCPAddr("tcp", listenAddr)
 	if err != nil {
 		return nil, err
diff --git a/lib/go/thrift/ssl_socket.go b/lib/go/thrift/ssl_socket.go
index 04d3850..2395986 100644
--- a/lib/go/thrift/ssl_socket.go
+++ b/lib/go/thrift/ssl_socket.go
@@ -48,6 +48,9 @@
 // NewTSSLSocketTimeout creates a net.Conn-backed TTransport, given a host and port
 // it also accepts a tls Configuration and a timeout as a time.Duration
 func NewTSSLSocketTimeout(hostPort string, cfg *tls.Config, timeout time.Duration) (*TSSLSocket, error) {
+	if cfg.MinVersion == 0 {
+		cfg.MinVersion = tls.VersionTLS10
+	}
 	return &TSSLSocket{hostPort: hostPort, timeout: timeout, cfg: cfg}, nil
 }
 
diff --git a/lib/nodejs/lib/thrift/connection.js b/lib/nodejs/lib/thrift/connection.js
index 575d516..608e552 100644
--- a/lib/nodejs/lib/thrift/connection.js
+++ b/lib/nodejs/lib/thrift/connection.js
@@ -18,6 +18,7 @@
  */
 var util = require('util');
 var EventEmitter = require("events").EventEmitter;
+var constants = require('constants');
 var net = require('net');
 var tls = require('tls');
 var thrift = require('./thrift');
@@ -221,7 +222,7 @@
   this.retry_timer = setTimeout(function () {
     if (self._debug) {
        console.log("Retrying connection...");
-	}
+  }
 
     self.retry_totaltime += self.retry_delay;
 
@@ -247,6 +248,11 @@
 };
 
 exports.createSSLConnection = function(host, port, options) {
+  if (!('secureProtocol' in options) && !('secureOptions' in options)) {
+    options.secureProtocol = "SSLv23_method";
+    options.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3;
+  }
+
   var stream = tls.connect(port, host, options);
   var connection = new Connection(stream, options);
   connection.host = host;
diff --git a/lib/nodejs/lib/thrift/server.js b/lib/nodejs/lib/thrift/server.js
index 921bb86..e124acc 100644
--- a/lib/nodejs/lib/thrift/server.js
+++ b/lib/nodejs/lib/thrift/server.js
@@ -16,6 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
+var constants = require('constants');
 var net = require('net');
 var tls = require('tls');
 
@@ -87,6 +89,10 @@
   }
 
   if (options && options.tls) {
+    if (!('secureProtocol' in options.tls) && !('secureOptions' in options.tls)) {
+      options.tls.secureProtocol = "SSLv23_method";
+      options.tls.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3;
+    }
     return tls.createServer(options.tls, serverImpl);
   } else {
     return net.createServer(serverImpl);
diff --git a/lib/perl/lib/Thrift/SSLServerSocket.pm b/lib/perl/lib/Thrift/SSLServerSocket.pm
index e885ede..a8dfa56 100644
--- a/lib/perl/lib/Thrift/SSLServerSocket.pm
+++ b/lib/perl/lib/Thrift/SSLServerSocket.pm
@@ -60,13 +60,15 @@
                 Proto         => 'tcp',
                 ReuseAddr     => 1};
 
+    my $verify = IO::Socket::SSL::SSL_VERIFY_PEER | IO::Socket::SSL::SSL_VERIFY_FAIL_IF_NO_PEER_CERT | IO::Socket::SSL::SSL_VERIFY_CLIENT_ONCE;
+
     $opts->{SSL_ca_file}      = $self->{ca}      if defined $self->{ca};
     $opts->{SSL_cert_file}    = $self->{cert}    if defined $self->{cert};
     $opts->{SSL_cipher_list}  = $self->{ciphers} if defined $self->{ciphers};
     $opts->{SSL_key_file}     = $self->{key}     if defined $self->{key};
     $opts->{SSL_use_cert}     = (defined $self->{cert}) ? 1 : 0;
-    $opts->{SSL_verify_mode}  = (defined $self->{ca}) ? IO::Socket::SSL::SSL_VERIFY_PEER : IO::Socket::SSL::SSL_VERIFY_NONE;
-    $opts->{SSL_version}      = (defined $self->{version}) ? $self->{version} : 'SSLv23:!SSLv2:!SSLv3';
+    $opts->{SSL_verify_mode}  = (defined $self->{ca}) ? $verify : IO::Socket::SSL::SSL_VERIFY_NONE;
+    $opts->{SSL_version}      = (defined $self->{version}) ? $self->{version} : 'SSLv23:!SSLv3:!SSLv2';
 
     return IO::Socket::SSL->new(%$opts);
 }
diff --git a/lib/perl/lib/Thrift/SSLSocket.pm b/lib/perl/lib/Thrift/SSLSocket.pm
index 046692e..99a4107 100644
--- a/lib/perl/lib/Thrift/SSLSocket.pm
+++ b/lib/perl/lib/Thrift/SSLSocket.pm
@@ -71,13 +71,15 @@
                 Proto         => 'tcp',
                 Timeout       => $self->{sendTimeout} / 1000};
 
+    my $verify = IO::Socket::SSL::SSL_VERIFY_PEER | IO::Socket::SSL::SSL_VERIFY_FAIL_IF_NO_PEER_CERT | IO::Socket::SSL::SSL_VERIFY_CLIENT_ONCE;
+
     $opts->{SSL_ca_file}      = $self->{ca}      if defined $self->{ca};
     $opts->{SSL_cert_file}    = $self->{cert}    if defined $self->{cert};
     $opts->{SSL_cipher_list}  = $self->{ciphers} if defined $self->{ciphers};
     $opts->{SSL_key_file}     = $self->{key}     if defined $self->{key};
     $opts->{SSL_use_cert}     = (defined $self->{cert}) ? 1 : 0;
-    $opts->{SSL_verify_mode}  = (defined $self->{ca}) ? IO::Socket::SSL::SSL_VERIFY_PEER : IO::Socket::SSL::SSL_VERIFY_NONE;
-    $opts->{SSL_version}      = (defined $self->{version}) ? $self->{version} : 'SSLv23:!SSLv2:!SSLv3';
+    $opts->{SSL_verify_mode}  = (defined $self->{ca}) ? $verify : IO::Socket::SSL::SSL_VERIFY_NONE;
+    $opts->{SSL_version}      = (defined $self->{version}) ? $self->{version} : 'SSLv23:!SSLv3:!SSLv2';
 
     return IO::Socket::SSL->new(%$opts);
 }