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);
}