Module: TunnelRb::Server::TLS

Defined in:
lib/tunnel_rb/server/tls.rb

Overview

Builds TLS contexts and wraps the control listener. TLS is optional: callers pass nil cert/key to run the control plane in plaintext.

Class Method Summary collapse

Class Method Details

.load_certificates(path) ⇒ Object

Wraps a TCPServer in an SSLServer. The handshake is deferred (start_immediately = false) so accept() does not block on a slow client; the worker thread performs the handshake instead.



33
34
35
36
37
38
39
# File 'lib/tunnel_rb/server/tls.rb', line 33

def load_certificates(path)
  File.read(path).scan(/-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/m).map do |pem|
    OpenSSL::X509::Certificate.new(pem)
  end.tap do |certs|
    raise "No certificates in #{path}" if certs.empty?
  end
end

.server_context(cert_path:, key_path:) ⇒ Object

Returns an SSLContext configured to present the given cert/key, or nil when either path is missing (TLS disabled).



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/tunnel_rb/server/tls.rb', line 14

def server_context(cert_path:, key_path:)
  return nil if cert_path.nil? || key_path.nil?

  ctx = OpenSSL::SSL::SSLContext.new
  certs = load_certificates(cert_path)
  ctx.cert = certs.shift
  ctx.extra_chain_cert = certs unless certs.empty?
  ctx.key = OpenSSL::PKey.read(File.read(key_path))
  ctx.min_version = OpenSSL::SSL::TLS1_3_VERSION

  # Enable session resumption: the server issues TLS 1.3 session tickets so
  # repeat data-socket handshakes skip the expensive signature/verify step.
  ctx.session_id_context = "tunnel-rb-server"
  ctx
end

.wrap_listener(tcp_server, ctx) ⇒ Object



41
42
43
44
45
# File 'lib/tunnel_rb/server/tls.rb', line 41

def wrap_listener(tcp_server, ctx)
  ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx)
  ssl_server.start_immediately = false
  ssl_server
end