From 38e5fde04e7e10425dcc17a95e36ced2dff3dffe Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Thu, 7 May 2015 22:09:09 -0700 Subject: [PATCH] Create our own self-signed certs, rather than letting Webrick do it for us. We now use a modified copy of Webrick's create_self_signed_certificate that generates a different certificate serial number each time (based on the current time). This avoids an error in Firefox when we serve a certificate with different details but the same serial: it throws up a "sec_error_reused_issuer_and_serial" error and refuses to let you accept the certificate. Our modified version also avoids printing garbage to $stderr. --- .../lib/middleman-core/preview_server.rb | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/middleman-core/lib/middleman-core/preview_server.rb b/middleman-core/lib/middleman-core/preview_server.rb index ce6678b7..3f869058 100644 --- a/middleman-core/lib/middleman-core/preview_server.rb +++ b/middleman-core/lib/middleman-core/preview_server.rb @@ -194,7 +194,9 @@ module Middleman http_opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new File.read ssl_private_key else # use a generated self-signed cert - http_opts[:SSLCertName] = [%w(CN localhost), %W(CN #{host})].uniq + cert, key = create_self_signed_cert(1024, [["CN", host]], "Middleman Preview Server") + http_opts[:SSLCertificate] = cert + http_opts[:SSLPrivateKey] = key end end @@ -212,6 +214,38 @@ module Middleman end end + # Copy of https://github.com/nahi/ruby/blob/webrick_trunk/lib/webrick/ssl.rb#L39 + # that uses a different serial number each time the cert is generated in order to + # avoid errors in Firefox. Also doesn't print out stuff to $stderr unnecessarily. + def create_self_signed_cert(bits, cn, comment) + rsa = OpenSSL::PKey::RSA.new(bits) + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = Time.now.to_i % (1 << 20) + name = OpenSSL::X509::Name.new(cn) + 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) + ef.issuer_certificate = cert + cert.extensions = [ + ef.create_extension("basicConstraints","CA:FALSE"), + ef.create_extension("keyUsage", "keyEncipherment"), + ef.create_extension("subjectKeyIdentifier", "hash"), + ef.create_extension("extendedKeyUsage", "serverAuth"), + ef.create_extension("nsComment", comment), + ] + aki = ef.create_extension("authorityKeyIdentifier", + "keyid:always,issuer:always") + cert.add_extension(aki) + cert.sign(rsa, OpenSSL::Digest::SHA1.new) + + return [ cert, rsa ] + end + # Attach a new Middleman::Application instance # @param [Middleman::Application] app # @return [void] @@ -273,7 +307,6 @@ module Middleman ip = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? } ip ? ip.ip_address : '127.0.0.1' end - end class FilteredWebrickLog < ::WEBrick::Log