test_name "CVE 2013-1654 SSL2 Downgrade of Agent connection" do

require 'puppet/acceptance/windows_utils'
extend Puppet::Acceptance::WindowsUtils

  def which_ruby(host)
    if host['platform'] =~ /windows/
      ruby_cmd(host)
    else
      host['puppetbindir'] ? "#{host['puppetbindir']}/ruby" : 'ruby'
    end
  end

  def suitable?(host)
    cmd = <<END
#{which_ruby(host)} -ropenssl -e "puts OpenSSL::SSL::SSLContext::METHODS.include?(:SSLv2)"
END
    on(host, cmd).stdout.chomp == "true"
  end

  agents.each do |agent|
    if suitable?( agent )
      certfile = on(agent, puppet_agent("--configprint hostcert")).stdout.chomp
      keyfile = on(agent, puppet_agent("--configprint hostprivkey")).stdout.chomp
      cafile = on(agent, puppet_agent("--configprint localcacert")).stdout.chomp
      port = 8150

      sslserver = <<END
#!/usr/bin/env ruby
require 'webrick'
require 'webrick/https'

class Servlet < WEBrick::HTTPServlet::AbstractServlet
  def do_GET(request, response)
    response.status = 200
    response['Content-Type'] = 'text/pson'
    response.body = 'FOOBAR'
  end
end

class SSLServer
  def run
    config = {}
    config[:Port] = #{port}
    config[:SSLCACertificateFile] = '#{cafile}'
    config[:SSLCertificate] =  OpenSSL::X509::Certificate.new(File.read('#{certfile}'))
    config[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(File.read('#{keyfile}'))
    config[:SSLStartImmediately] = true
    config[:SSLEnable] = true
    config[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_NONE

    server = WEBrick::HTTPServer.new(config)
    server.mount('/', Servlet)
    server.ssl_context.ssl_version = 'SSLv2'
    trap :TERM do
      exit!(0)
    end
    server.start
  end
end

if $0 == __FILE__
  SSLServer.new.run
end
END
      testdir = agent.tmpdir('puppet-sslv2')
      teardown do
        sslserver_in_process_list = agent["platform"] =~ /win/ ? 'ruby' : 'sslserver.rb'
        on(agent, "ps -ef | grep #{sslserver_in_process_list} | grep -v grep | awk '{ print $2 }' | xargs kill || echo \"ruby sslserver.rb not running\"")
        on(agent, "rm -rf #{testdir}")
      end

      create_remote_file(agent, "#{testdir}/sslserver.rb", sslserver)
      on agent, "#{which_ruby(agent)} #{testdir}/sslserver.rb &>/dev/null &"

      timeout = 15
      begin
        Timeout.timeout(timeout) do
          loop do
            # 7 is "Could not connect to host", which will happen before it's running
            # 28 is "Operation timeout", which could happen if the vm was running slowly
            result = on(agent, "curl --tlsv1 -m1 -k https://#{agent}:#{port}", :acceptable_exit_codes => [0,7,28,35])
            break if result.exit_code == 0 or result.exit_code == 35
            sleep 1
          end
        end
      rescue Timeout::Error
        fail_test "Insecure Mock Server on #{agent} failed to start after #{timeout} seconds"
      end

      on(agent, puppet("agent --debug --test --server #{agent} --masterport #{port}"), :acceptable_exit_codes => [1]) do |test|
        assert_no_match(/'FOOBAR'/, test.stdout)
      end
    else
      logger.debug( "skipping #{agent} since SSLv2 is not available" )
    end
  end
end
