2016-08-15 05:15:06 +00:00
|
|
|
# encoding: utf-8
|
|
|
|
# copyright: 2015, Chef Software Inc.
|
|
|
|
|
|
|
|
require 'sslshake'
|
|
|
|
require 'utils/filter'
|
2016-09-06 20:45:52 +00:00
|
|
|
require 'uri'
|
|
|
|
require 'parallel'
|
2016-08-15 05:15:06 +00:00
|
|
|
|
|
|
|
# Custom resource based on the InSpec resource DSL
|
|
|
|
class SSL < Inspec.resource(1)
|
|
|
|
name 'ssl'
|
2018-02-19 14:26:49 +00:00
|
|
|
supports platform: 'unix'
|
|
|
|
supports platform: 'windows'
|
2016-08-15 05:15:06 +00:00
|
|
|
|
|
|
|
desc "
|
|
|
|
SSL test resource
|
|
|
|
"
|
|
|
|
|
|
|
|
example "
|
|
|
|
describe ssl(port: 443) do
|
|
|
|
it { should be_enabled }
|
|
|
|
end
|
|
|
|
|
|
|
|
# protocols: ssl2, ssl3, tls1.0, tls1.1, tls1.2
|
|
|
|
describe ssl(port: 443).protocols('ssl2') do
|
|
|
|
it { should_not be_enabled }
|
|
|
|
end
|
|
|
|
|
|
|
|
# any ciphers, filter by name or regex
|
|
|
|
describe ssl(port: 443).ciphers(/rc4/i) do
|
|
|
|
it { should_not be_enabled }
|
|
|
|
end
|
|
|
|
"
|
|
|
|
|
|
|
|
VERSIONS = [
|
|
|
|
'ssl2',
|
|
|
|
'ssl3',
|
|
|
|
'tls1.0',
|
|
|
|
'tls1.1',
|
|
|
|
'tls1.2',
|
|
|
|
].freeze
|
|
|
|
|
2016-10-26 16:19:56 +00:00
|
|
|
attr_reader :host, :port, :timeout, :retries
|
2016-08-15 05:15:06 +00:00
|
|
|
|
|
|
|
def initialize(opts = {})
|
2016-09-16 09:41:22 +00:00
|
|
|
@host = opts[:host]
|
2016-08-15 05:15:06 +00:00
|
|
|
if @host.nil?
|
2016-09-16 09:41:22 +00:00
|
|
|
# Transports like SSH and WinRM will provide a hostname
|
|
|
|
if inspec.backend.respond_to?('hostname')
|
|
|
|
@host = inspec.backend.hostname
|
|
|
|
elsif inspec.backend.class.to_s == 'Train::Transports::Local::Connection'
|
|
|
|
@host = 'localhost'
|
|
|
|
end
|
2016-08-15 05:15:06 +00:00
|
|
|
end
|
|
|
|
@port = opts[:port] || 443
|
|
|
|
@timeout = opts[:timeout]
|
|
|
|
@retries = opts[:retries]
|
|
|
|
end
|
|
|
|
|
|
|
|
filter = FilterTable.create
|
2018-06-26 19:14:21 +00:00
|
|
|
filter.register_custom_matcher(:enabled?) do |x|
|
2017-10-06 17:38:22 +00:00
|
|
|
raise 'Cannot determine host for SSL test. Please specify it or use a different target.' if x.resource.host.nil?
|
|
|
|
x.handshake.values.any? { |i| i['success'] }
|
|
|
|
end
|
2018-06-26 19:14:21 +00:00
|
|
|
filter.register_column(:ciphers, field: 'cipher')
|
|
|
|
.register_column(:protocols, field: 'protocol')
|
|
|
|
.register_custom_property(:handshake) { |x|
|
2016-08-15 05:15:06 +00:00
|
|
|
groups = x.entries.group_by(&:protocol)
|
2016-09-06 20:45:52 +00:00
|
|
|
res = Parallel.map(groups, in_threads: 8) do |proto, e|
|
2016-08-15 05:15:06 +00:00
|
|
|
[proto, SSLShake.hello(x.resource.host, port: x.resource.port,
|
|
|
|
protocol: proto, ciphers: e.map(&:cipher),
|
2017-04-04 09:09:15 +00:00
|
|
|
timeout: x.resource.timeout, retries: x.resource.retries, servername: x.resource.host)]
|
2016-08-15 05:15:06 +00:00
|
|
|
end
|
|
|
|
Hash[res]
|
|
|
|
}
|
2018-06-26 19:14:21 +00:00
|
|
|
.install_filter_methods_on_resource(self, :scan_config)
|
2016-08-15 05:15:06 +00:00
|
|
|
|
|
|
|
def to_s
|
|
|
|
"SSL/TLS on #{@host}:#{@port}"
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def scan_config
|
|
|
|
[
|
|
|
|
{ 'protocol' => 'ssl2', 'ciphers' => SSLShake::SSLv2::CIPHERS.keys },
|
|
|
|
{ 'protocol' => 'ssl3', 'ciphers' => SSLShake::TLS::SSL3_CIPHERS.keys },
|
|
|
|
{ 'protocol' => 'tls1.0', 'ciphers' => SSLShake::TLS::TLS10_CIPHERS.keys },
|
|
|
|
{ 'protocol' => 'tls1.1', 'ciphers' => SSLShake::TLS::TLS10_CIPHERS.keys },
|
|
|
|
{ 'protocol' => 'tls1.2', 'ciphers' => SSLShake::TLS::TLS_CIPHERS.keys },
|
|
|
|
].map do |line|
|
|
|
|
line['ciphers'].map do |cipher|
|
|
|
|
{ 'protocol' => line['protocol'], 'cipher' => cipher }
|
|
|
|
end
|
|
|
|
end.flatten
|
|
|
|
end
|
|
|
|
end
|