class Ritm::Proxy::CertSigningHTTPSServer
Patches WEBrick::HTTPServer
SSL context creation to get a callback on the 'Client Helo' step of the SSL-Handshake if SNI is specified So RitM can create self-signed certificates on the fly
Public Instance Methods
setup_ssl_context(config)
click to toggle source
Override
Calls superclass method
# File lib/ritm/proxy/cert_signing_https_server.rb, line 15 def setup_ssl_context(config) ctx = super(config) prepare_sni_callback(ctx, config[:ca]) ctx end
Private Instance Methods
context_with_cert(original_ctx, cert)
click to toggle source
# File lib/ritm/proxy/cert_signing_https_server.rb, line 46 def context_with_cert(original_ctx, cert) ctx = duplicate_context(original_ctx) ctx.key = cert.private_key ctx.cert = cert.x509 ctx end
duplicate_context(original_ctx)
click to toggle source
# File lib/ritm/proxy/cert_signing_https_server.rb, line 53 def duplicate_context(original_ctx) return original_ctx.dup unless IS_RUBY_2_4_OR_OLDER ctx = OpenSSL::SSL::SSLContext.new original_ctx.instance_variables.each do |variable_name| prop_name = variable_name.to_s.sub(/^@/, '') set_prop_method = "#{prop_name}=" ctx.send(set_prop_method, original_ctx.send(prop_name)) if ctx.respond_to? set_prop_method end ctx end
prepare_sni_callback(ctx, ca)
click to toggle source
Keeps track of the created self-signed certificates TODO: this can grow a lot and take up memory, fix by either:
-
implementing wildcard certificates generation (so there's one certificate per top level domain)
-
Use the same key material (private/public keys) for all the server names and just do the signing on-the-fly
-
both of the above
# File lib/ritm/proxy/cert_signing_https_server.rb, line 28 def prepare_sni_callback(ctx, ca) contexts = {} mutex = Mutex.new # Sets the SNI callback on the SSLTCPSocket ctx.servername_cb = proc do |sock, servername| mutex.synchronize do unless contexts.include? servername cert = Ritm::Certificate.create(servername) cert.cert.extensions['subjectAltName'].dns_names = [servername] ca.sign(cert) contexts[servername] = context_with_cert(sock.context, cert) end end contexts[servername] end end