class Plum::Rack::TLSListener
Public Class Methods
new(lc)
click to toggle source
# File lib/plum/rack/listener.rb, line 52 def initialize(lc) if lc[:certificate] && lc[:certificate_key] cert = File.read(lc[:certificate]) key = File.read(lc[:certificate_key]) else STDERR.puts "WARNING: using dummy certificate" cert, key = dummy_key end ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = :TLSv1_2 ctx.alpn_select_cb = -> (protocols) { protocols.include?("h2") ? "h2" : protocols.first } ctx.tmp_ecdh_callback = -> (sock, ise, keyl) { OpenSSL::PKey::EC.new("prime256v1") } *ctx.extra_chain_cert, ctx.cert = parse_chained_cert(cert) ctx.key = OpenSSL::PKey::RSA.new(key) ctx.servername_cb = proc { |sock, hostname| if host = lc[:sni]&.[](hostname) new_ctx = ctx.dup *new_ctx.extra_chain_cert, new_ctx.cert = parse_chained_cert(File.read(host[:certificate])) new_ctx.key = OpenSSL::PKey::RSA.new(File.read(host[:certificate_key])) new_ctx else ctx end } tcp_server = ::TCPServer.new(lc[:hostname], lc[:port]) @server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx) @server.start_immediately = false # call socket#accept twice: [tcp, tls] end
Public Instance Methods
accept(svc)
click to toggle source
# File lib/plum/rack/listener.rb, line 90 def accept(svc) sock = @server.accept Thread.start { begin sock = sock.accept raise ::Plum::LegacyHTTPError.new("client didn't offer h2 with ALPN", nil) unless sock.alpn_protocol == "h2" plum = ::Plum::ServerConnection.new(sock.method(:write)) sess = Session.new(svc, sock, plum) sess.run rescue ::Plum::LegacyHTTPError => e svc.logger.info "legacy HTTP client: #{e}" sess = LegacySession.new(svc, e, sock) sess.run rescue Errno::ECONNRESET, EOFError # closed rescue => e svc.log_exception(e) ensure sock.close if sock end } end
parse_chained_cert(str)
click to toggle source
# File lib/plum/rack/listener.rb, line 82 def parse_chained_cert(str) str.scan(/-----BEGIN CERTIFICATE.+?END CERTIFICATE-----/m).map { |s| OpenSSL::X509::Certificate.new(s) } end
to_io()
click to toggle source
# File lib/plum/rack/listener.rb, line 86 def to_io @server.to_io end
Private Instance Methods
dummy_key()
click to toggle source
returns: [cert, key]
# File lib/plum/rack/listener.rb, line 114 def dummy_key STDERR.puts "WARNING: Generating new dummy certificate..." key = OpenSSL::PKey::RSA.new(2048) cert = OpenSSL::X509::Certificate.new cert.subject = cert.issuer = OpenSSL::X509::Name.parse("/C=JP/O=Test/OU=Test/CN=example.com") cert.not_before = Time.now cert.not_after = Time.now + 363 * 24 * 60 * 60 cert.public_key = key.public_key cert.serial = rand((1 << 20) - 1) cert.version = 2 ef = OpenSSL::X509::ExtensionFactory.new ef.subject_certificate = cert ef.issuer_certificate = cert cert.extensions = [ ef.create_extension("basicConstraints", "CA:TRUE", true), ] cert.sign(key, OpenSSL::Digest::SHA256.new) [cert.to_s, key.to_s] end