Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server Name Indication (Let's Encrypt / Server only certificate) support for Ruby, Python and Java drivers #6204

Open
wants to merge 5 commits into
base: v2.4.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions drivers/java/src/main/java/com/rethinkdb/net/SocketWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import com.rethinkdb.gen.exc.ReqlDriverError;

import javax.net.SocketFactory;
import javax.net.ssl.SNIHostName;
import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.DataInputStream;
Expand All @@ -14,7 +17,9 @@
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Optional;
import java.util.List;

public class SocketWrapper {
// networking stuff
Expand Down Expand Up @@ -63,6 +68,15 @@ void connect(Handshake handshake) {
socket.getPort(),
true);

// SNI support, Java 8 only
SNIHostName serverName = new SNIHostName(hostname);
List<SNIServerName> serverNames = new ArrayList<>(1);
serverNames.add(serverName);

SSLParameters params = sslSocket.getSSLParameters();
params.setServerNames(serverNames);
sslSocket.setSSLParameters(params);

// replace input/output streams
readStream = new DataInputStream(sslSocket.getInputStream());
writeStream = sslSocket.getOutputStream();
Expand Down
10 changes: 6 additions & 4 deletions drivers/python/rethinkdb/net.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ def __init__(self, parent, timeout):
self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

if len(self.ssl) > 0:
if self.ssl is not None:
try:
if hasattr(ssl, 'SSLContext'): # Python2.7 and 3.2+, or backports.ssl
ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
Expand All @@ -289,7 +289,11 @@ def __init__(self, parent, timeout):
ssl_context.options |= getattr(ssl, "OP_NO_SSLv3", 0)
ssl_context.verify_mode = ssl.CERT_REQUIRED
ssl_context.check_hostname = True # redundant with match_hostname
ssl_context.load_verify_locations(self.ssl["ca_certs"])
if "ca_certs" not in self.ssl:
#Use system certs
ssl_context.load_default_certs()
else:
ssl_context.load_verify_locations(self.ssl["ca_certs"])
self._socket = ssl_context.wrap_socket(self._socket, server_hostname=self.host)
else: # this does not disable SSLv2 or SSLv3
self._socket = ssl.wrap_socket(
Expand Down Expand Up @@ -663,8 +667,6 @@ def connect(host=None, port=None, db=None, auth_key=None, user=None, password=No
user = 'admin'
if timeout is None:
timeout = 20
if ssl is None:
ssl = dict()
if _handshake_version is None:
_handshake_version = 10

Expand Down
14 changes: 8 additions & 6 deletions drivers/ruby/lib/net.rb
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ def initialize(opts={})
@nonce = SecureRandom.base64(18)
@timeout = opts[:timeout].to_i
@timeout = 20 if @timeout <= 0
@ssl_opts = opts[:ssl] || {}
@ssl_opts = opts[:ssl] || nil

@@last = self
@default_opts = @default_db ? {:db => RQL.new.db(@default_db)} : {}
Expand Down Expand Up @@ -690,11 +690,12 @@ def connect()
end

def init_socket
unless @ssl_opts.empty?
unless @ssl_opts.nil?
@tcp_socket = base_socket
context = create_context(@ssl_opts)
@socket = OpenSSL::SSL::SSLSocket.new(@tcp_socket, context)
@socket.sync_close = true
@socket.hostname = @host
@socket.connect
verify_cert!(@socket, context)
else
Expand All @@ -712,12 +713,13 @@ def base_socket
def create_context(options)
context = OpenSSL::SSL::SSLContext.new
context.ssl_version = :TLSv1_2
if options[:ca_certs]
if @ssl_opts.empty?
#Assume system certs
context.ca_file = OpenSSL::X509::DEFAULT_CERT_FILE
elsif options[:ca_certs]
context.ca_file = options[:ca_certs]
context.verify_mode = OpenSSL::SSL::VERIFY_PEER
else
raise 'ssl options provided but missing required "ca_certs" option'
end
context.verify_mode = OpenSSL::SSL::VERIFY_PEER
context
end

Expand Down