Sha256: bf2c5ac042f5c173c3eb72e85054dc21a1c42f697ddacd61e4e25f8f6ad94eb4

Contents?: true

Size: 1.79 KB

Versions: 1

Compression:

Stored size: 1.79 KB

Contents

require "net/https"

module SSLTest
  VERSION = "1.2.0"

  def self.test url, open_timeout: 5, read_timeout: 5
    uri = URI.parse(url)
    return if uri.scheme != 'https'
    cert = failed_cert_reason = nil

    http = Net::HTTP.new(uri.host, uri.port)
    http.open_timeout = open_timeout
    http.read_timeout = read_timeout
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_PEER
    http.verify_callback = -> (verify_ok, store_context) {
      cert = store_context.current_cert
      failed_cert_reason = [store_context.error, store_context.error_string] if store_context.error != 0
      verify_ok
    }

    begin
      http.start { }
      return [true, nil, cert]
    rescue OpenSSL::SSL::SSLError => e
      error = e.message
      error = "error code %d: %s" % failed_cert_reason if failed_cert_reason
      if error =~ /certificate verify failed/
        domains = cert_domains(cert)
        if matching_domains(domains, uri.host).none?
          error = "hostname \"#{uri.host}\" does not match the server certificate (#{domains.join(', ')})"
        end
      end
      return [false, error, cert]
    rescue => e
      return [nil, "SSL certificate test failed: #{e.message}"]
    end
  end

  def self.cert_field_to_hash field
    field.to_a.each.with_object({}) do |v, h|
      v = v.to_a
      h[v[0]] = v[1].encode('UTF-8', undef: :replace, invalid: :replace)
    end
  end

  def self.cert_domains cert
    (Array(cert_field_to_hash(cert.subject)['CN']) +
      cert_field_to_hash(cert.extensions)['subjectAltName'].split(/\s*,\s*/))
      .compact
      .map {|s| s.gsub(/^DNS:/, '') }
      .uniq
  end

  def self.matching_domains domains, hostname
    domains.map {|s| Regexp.new("\A#{Regexp.escape(s).gsub('\*', '[^.]+')}\z") }
      .select {|domain| domain.match?(hostname) }
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
ssl-test-1.2.0 lib/ssl-test.rb