1# frozen_string_literal: false 2# 3# ssl.rb -- SSL/TLS enhancement for GenericServer 4# 5# Copyright (c) 2003 GOTOU Yuuzou All rights reserved. 6# 7# $Id: ssl.rb 66152 2018-12-03 04:51:08Z normal $ 8 9require 'webrick' 10require 'openssl' 11 12module WEBrick 13 module Config 14 svrsoft = General[:ServerSoftware] 15 osslv = ::OpenSSL::OPENSSL_VERSION.split[1] 16 17 ## 18 # Default SSL server configuration. 19 # 20 # WEBrick can automatically create a self-signed certificate if 21 # <code>:SSLCertName</code> is set. For more information on the various 22 # SSL options see OpenSSL::SSL::SSLContext. 23 # 24 # :ServerSoftware :: 25 # The server software name used in the Server: header. 26 # :SSLEnable :: false, 27 # Enable SSL for this server. Defaults to false. 28 # :SSLCertificate :: 29 # The SSL certificate for the server. 30 # :SSLPrivateKey :: 31 # The SSL private key for the server certificate. 32 # :SSLClientCA :: nil, 33 # Array of certificates that will be sent to the client. 34 # :SSLExtraChainCert :: nil, 35 # Array of certificates that will be added to the certificate chain 36 # :SSLCACertificateFile :: nil, 37 # Path to a CA certificate file 38 # :SSLCACertificatePath :: nil, 39 # Path to a directory containing CA certificates 40 # :SSLCertificateStore :: nil, 41 # OpenSSL::X509::Store used for certificate validation of the client 42 # :SSLTmpDhCallback :: nil, 43 # Callback invoked when DH parameters are required. 44 # :SSLVerifyClient :: 45 # Sets whether the client is verified. This defaults to VERIFY_NONE 46 # which is typical for an HTTPS server. 47 # :SSLVerifyDepth :: 48 # Number of CA certificates to walk when verifying a certificate chain 49 # :SSLVerifyCallback :: 50 # Custom certificate verification callback 51 # :SSLServerNameCallback:: 52 # Custom servername indication callback 53 # :SSLTimeout :: 54 # Maximum session lifetime 55 # :SSLOptions :: 56 # Various SSL options 57 # :SSLCiphers :: 58 # Ciphers to be used 59 # :SSLStartImmediately :: 60 # Immediately start SSL upon connection? Defaults to true 61 # :SSLCertName :: 62 # SSL certificate name. Must be set to enable automatic certificate 63 # creation. 64 # :SSLCertComment :: 65 # Comment used during automatic certificate creation. 66 67 SSL = { 68 :ServerSoftware => "#{svrsoft} OpenSSL/#{osslv}", 69 :SSLEnable => false, 70 :SSLCertificate => nil, 71 :SSLPrivateKey => nil, 72 :SSLClientCA => nil, 73 :SSLExtraChainCert => nil, 74 :SSLCACertificateFile => nil, 75 :SSLCACertificatePath => nil, 76 :SSLCertificateStore => nil, 77 :SSLTmpDhCallback => nil, 78 :SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE, 79 :SSLVerifyDepth => nil, 80 :SSLVerifyCallback => nil, # custom verification 81 :SSLTimeout => nil, 82 :SSLOptions => nil, 83 :SSLCiphers => nil, 84 :SSLStartImmediately => true, 85 # Must specify if you use auto generated certificate. 86 :SSLCertName => nil, 87 :SSLCertComment => "Generated by Ruby/OpenSSL" 88 } 89 General.update(SSL) 90 end 91 92 module Utils 93 ## 94 # Creates a self-signed certificate with the given number of +bits+, 95 # the issuer +cn+ and a +comment+ to be stored in the certificate. 96 97 def create_self_signed_cert(bits, cn, comment) 98 rsa = OpenSSL::PKey::RSA.new(bits){|p, n| 99 case p 100 when 0; $stderr.putc "." # BN_generate_prime 101 when 1; $stderr.putc "+" # BN_generate_prime 102 when 2; $stderr.putc "*" # searching good prime, 103 # n = #of try, 104 # but also data from BN_generate_prime 105 when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q, 106 # but also data from BN_generate_prime 107 else; $stderr.putc "*" # BN_generate_prime 108 end 109 } 110 cert = OpenSSL::X509::Certificate.new 111 cert.version = 2 112 cert.serial = 1 113 name = (cn.kind_of? String) ? OpenSSL::X509::Name.parse(cn) 114 : OpenSSL::X509::Name.new(cn) 115 cert.subject = name 116 cert.issuer = name 117 cert.not_before = Time.now 118 cert.not_after = Time.now + (365*24*60*60) 119 cert.public_key = rsa.public_key 120 121 ef = OpenSSL::X509::ExtensionFactory.new(nil,cert) 122 ef.issuer_certificate = cert 123 cert.extensions = [ 124 ef.create_extension("basicConstraints","CA:FALSE"), 125 ef.create_extension("keyUsage", "keyEncipherment"), 126 ef.create_extension("subjectKeyIdentifier", "hash"), 127 ef.create_extension("extendedKeyUsage", "serverAuth"), 128 ef.create_extension("nsComment", comment), 129 ] 130 aki = ef.create_extension("authorityKeyIdentifier", 131 "keyid:always,issuer:always") 132 cert.add_extension(aki) 133 cert.sign(rsa, OpenSSL::Digest::SHA256.new) 134 135 return [ cert, rsa ] 136 end 137 module_function :create_self_signed_cert 138 end 139 140 ## 141 #-- 142 # Updates WEBrick::GenericServer with SSL functionality 143 144 class GenericServer 145 146 ## 147 # SSL context for the server when run in SSL mode 148 149 def ssl_context # :nodoc: 150 @ssl_context ||= begin 151 if @config[:SSLEnable] 152 ssl_context = setup_ssl_context(@config) 153 @logger.info("\n" + @config[:SSLCertificate].to_text) 154 ssl_context 155 end 156 end 157 end 158 159 undef listen 160 161 ## 162 # Updates +listen+ to enable SSL when the SSL configuration is active. 163 164 def listen(address, port) # :nodoc: 165 listeners = Utils::create_listeners(address, port) 166 if @config[:SSLEnable] 167 listeners.collect!{|svr| 168 ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context) 169 ssvr.start_immediately = @config[:SSLStartImmediately] 170 ssvr 171 } 172 end 173 @listeners += listeners 174 setup_shutdown_pipe 175 end 176 177 ## 178 # Sets up an SSL context for +config+ 179 180 def setup_ssl_context(config) # :nodoc: 181 unless config[:SSLCertificate] 182 cn = config[:SSLCertName] 183 comment = config[:SSLCertComment] 184 cert, key = Utils::create_self_signed_cert(2048, cn, comment) 185 config[:SSLCertificate] = cert 186 config[:SSLPrivateKey] = key 187 end 188 ctx = OpenSSL::SSL::SSLContext.new 189 ctx.key = config[:SSLPrivateKey] 190 ctx.cert = config[:SSLCertificate] 191 ctx.client_ca = config[:SSLClientCA] 192 ctx.extra_chain_cert = config[:SSLExtraChainCert] 193 ctx.ca_file = config[:SSLCACertificateFile] 194 ctx.ca_path = config[:SSLCACertificatePath] 195 ctx.cert_store = config[:SSLCertificateStore] 196 ctx.tmp_dh_callback = config[:SSLTmpDhCallback] 197 ctx.verify_mode = config[:SSLVerifyClient] 198 ctx.verify_depth = config[:SSLVerifyDepth] 199 ctx.verify_callback = config[:SSLVerifyCallback] 200 ctx.servername_cb = config[:SSLServerNameCallback] || proc { |args| ssl_servername_callback(*args) } 201 ctx.timeout = config[:SSLTimeout] 202 ctx.options = config[:SSLOptions] 203 ctx.ciphers = config[:SSLCiphers] 204 ctx 205 end 206 207 ## 208 # ServerNameIndication callback 209 210 def ssl_servername_callback(sslsocket, hostname = nil) 211 # default 212 end 213 214 end 215end 216