summaryrefslogtreecommitdiff
path: root/lib/webrick/https.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/webrick/https.rb')
-rw-r--r--lib/webrick/https.rb158
1 files changed, 158 insertions, 0 deletions
diff --git a/lib/webrick/https.rb b/lib/webrick/https.rb
new file mode 100644
index 0000000000..00fd469f1b
--- /dev/null
+++ b/lib/webrick/https.rb
@@ -0,0 +1,158 @@
+#
+# https.rb -- SSL/TLS enhancement for HTTPServer
+#
+# Author: IPR -- Internet Programming with Ruby -- writers
+# Copyright (c) 2001 GOTOU Yuuzou
+# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
+# reserved.
+#
+# $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $
+
+require 'webrick'
+require 'openssl'
+
+module WEBrick
+ module Config
+ HTTP.update(
+ :SSLEnable => true,
+ :SSLCertificate => nil,
+ :SSLPrivateKey => nil,
+ :SSLClientCA => nil,
+ :SSLCACertificateFile => nil,
+ :SSLCACertificatePath => nil,
+ :SSLCertStore => nil,
+ :SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
+ :SSLVerifyDepth => nil,
+ :SSLVerifyCallback => nil, # custom verification
+ :SSLTimeout => nil,
+ :SSLOptions => nil,
+ # Must specify if you use auto generated certificate.
+ :SSLCertName => nil,
+ :SSLCertComment => "Generated by Ruby/OpenSSL"
+ )
+
+ osslv = ::OpenSSL::OPENSSL_VERSION.split[1]
+ HTTP[:ServerSoftware] << " OpenSSL/#{osslv}"
+ end
+
+ class HTTPRequest
+ attr_reader :cipher, :server_cert, :client_cert
+
+ alias orig_parse parse
+
+ def parse(socket=nil)
+ orig_parse(socket)
+ @cipher = socket.respond_to?(:cipher) ? socket.cipher : nil
+ @client_cert = socket.respond_to?(:peer_cert) ? socket.peer_cert : nil
+ @server_cert = @config[:SSLCertificate]
+ end
+
+ alias orig_parse_uri parse_uri
+
+ def parse_uri(str, scheme="https")
+ if @config[:SSLEnable]
+ return orig_parse_uri(str, scheme)
+ end
+ return orig_parse_uri(str)
+ end
+
+ alias orig_meta_vars meta_vars
+
+ def meta_vars
+ meta = orig_meta_vars
+ if @config[:SSLEnable]
+ meta["HTTPS"] = "on"
+ meta["SSL_CIPHER"] = @cipher ? @cipher[0] : ""
+ meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : ""
+ meta["SSL_SERVER_CERT"] = @server_cert ? @server_cert.to_pem : ""
+ end
+ meta
+ end
+ end
+
+ class HTTPServer
+ alias orig_init initialize
+
+ def initialize(*args)
+ orig_init(*args)
+
+ if @config[:SSLEnable]
+ unless @config[:SSLCertificate]
+ rsa = OpenSSL::PKey::RSA.new(512){|p, n|
+ case p
+ when 0; $stderr.putc "." # BN_generate_prime
+ when 1; $stderr.putc "+" # BN_generate_prime
+ when 2; $stderr.putc "*" # searching good prime,
+ # n = #of try,
+ # but also data from BN_generate_prime
+ when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
+ # but also data from BN_generate_prime
+ else; $stderr.putc "*" # BN_generate_prime
+ end
+ }
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 3
+ cert.serial = 0
+ name = OpenSSL::X509::Name.new(@config[:SSLCertName])
+ cert.subject = name
+ cert.issuer = name
+ cert.not_before = Time.now
+ cert.not_after = Time.now + (365*24*60*60)
+ cert.public_key = rsa.public_key
+
+ ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
+ cert.extensions = [
+ ef.create_extension("basicConstraints","CA:FALSE"),
+ ef.create_extension("subjectKeyIdentifier", "hash"),
+ ef.create_extension("extendedKeyUsage", "serverAuth")
+ ]
+ ef.issuer_certificate = cert
+ ext = ef.create_extension("authorityKeyIdentifier",
+ "keyid:always,issuer:always")
+ cert.add_extension(ext)
+ if comment = @config[:SSLCertComment]
+ cert.add_extension(ef.create_extension("nsComment", comment))
+ end
+ cert.sign(rsa, OpenSSL::Digest::SHA1.new)
+
+ @config[:SSLPrivateKey] = rsa
+ @config[:SSLCertificate] = cert
+ @logger.info cert.to_s
+ end
+ @ctx = OpenSSL::SSL::SSLContext.new
+ set_ssl_context(@ctx, @config)
+ end
+ end
+
+ alias orig_run run
+
+ def run(sock)
+ if @config[:SSLEnable]
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
+ ssl.accept
+ Thread.current[:WEBrickSocket] = ssl
+ orig_run(ssl)
+ Thread.current[:WEBrickSocket] = sock
+ ssl.close
+ else
+ orig_run(sock)
+ end
+ end
+
+ private
+
+ def set_ssl_context(ctx, config)
+ ctx.key = config[:SSLPrivateKey]
+ ctx.cert = config[:SSLCertificate]
+ ctx.client_ca = config[:SSLClientCA]
+ ctx.ca_file = config[:SSLCACertificateFile]
+ ctx.ca_path = config[:SSLCACertificatePath]
+ ctx.cert_store = config[:SSLCertStore]
+ ctx.verify_mode = config[:SSLVerifyClient]
+ ctx.verify_depth = config[:SSLVerifyDepth]
+ ctx.verify_callback = config[:SSLVerifyCallback]
+ ctx.timeout = config[:SSLTimeout]
+ ctx.options = config[:SSLOptions]
+ end
+ end
+end