Handle SSL/TLS timeout
parent
ffa44a0043
commit
b62ef5192b
|
@ -4,4 +4,8 @@ Gemfile.lock
|
|||
/html/
|
||||
/.rspec
|
||||
/rakefile
|
||||
/output/index.html
|
||||
/output/*.html
|
||||
/db/*.sqlite3
|
||||
/db/schema.rb
|
||||
/lib/*.so
|
||||
/lib/*.so.1.0.0
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -7,6 +7,8 @@ gem 'tcp_timeout'
|
|||
gem 'parallel'
|
||||
gem 'ruby-progressbar'
|
||||
gem 'logging'
|
||||
gem 'activerecord'
|
||||
gem 'sqlite3'
|
||||
|
||||
group :test do
|
||||
gem 'rspec'
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
PWD = $(shell pwd)
|
||||
export CPATH = $(PWD)/openssl/include
|
||||
export LIBRARY_PATH = $(PWD)/openssl
|
||||
OPENSSL_VERSION = OpenSSL_1_0_1j
|
||||
RUBY_VERSION = 2.1.5
|
||||
RUBY_OPENSSL_EXT_DIR = ruby-$(RUBY_VERSION)/ext/openssl
|
||||
|
||||
all: lib/libssl.so.1.0.0 lib/libcrypto.so.1.0.0 lib/openssl.so
|
||||
|
||||
clean:
|
||||
rm -rf ruby-$(RUBY_VERSION) openssl
|
||||
|
||||
openssl:
|
||||
git clone https://github.com/openssl/openssl -b $(OPENSSL_VERSION)
|
||||
|
||||
openssl/Makefile: openssl
|
||||
cd openssl; ./config shared
|
||||
|
||||
openssl/libssl.so: openssl/Makefile
|
||||
cd openssl; $(MAKE) depend all
|
||||
|
||||
lib/%.so.1.0.0: openssl/%.so
|
||||
cp $^ $@
|
||||
|
||||
ruby-$(RUBY_VERSION):
|
||||
wget http://cache.ruby-lang.org/pub/ruby/2.1/ruby-$(RUBY_VERSION).tar.gz
|
||||
tar xf ruby-$(RUBY_VERSION).tar.gz
|
||||
rm -f ruby-$(RUBY_VERSION).tar.gz
|
||||
|
||||
$(RUBY_OPENSSL_EXT_DIR)/Makefile: ruby-$(RUBY_VERSION)
|
||||
cd $(RUBY_OPENSSL_EXT_DIR); ruby extconf.rb
|
||||
patch $@ patch
|
||||
|
||||
$(RUBY_OPENSSL_EXT_DIR)/openssl.so: $(RUBY_OPENSSL_EXT_DIR)/Makefile
|
||||
cd $(RUBY_OPENSSL_EXT_DIR); $(MAKE); $(MAKE) install
|
||||
|
||||
lib/openssl.so: $(RUBY_OPENSSL_EXT_DIR)/openssl.so
|
||||
cp $< $@
|
10
hosts.yml
10
hosts.yml
|
@ -15,11 +15,13 @@
|
|||
- description: Banques en ligne
|
||||
hostnames:
|
||||
- www.labanquepostale.fr
|
||||
- www.labanquepostale-cartesprepayees.fr
|
||||
- www.secure.bnpparibas.net
|
||||
- www.axabanque.fr
|
||||
- www.fortuneo.fr
|
||||
- www.ca-paris.fr
|
||||
- www.credit-cooperatif.coop
|
||||
- www.coopanet.com
|
||||
- www.cic.fr
|
||||
- particuliers.societegenerale.fr
|
||||
- espaceclient.groupama.fr
|
||||
|
@ -36,7 +38,7 @@
|
|||
- www.ca-paris.fr
|
||||
- www.ca-cotesdarmor.fr
|
||||
- secure.ingdirect.fr
|
||||
- banque-accord.fr
|
||||
- www.banque-accord.fr
|
||||
- espace-client-secure.banque-casino.fr
|
||||
- bforbank.com
|
||||
- hellobank.fr
|
||||
|
@ -46,9 +48,9 @@
|
|||
- zimbra.free.fr
|
||||
- webmail.numericable.fr
|
||||
- webmail.orange-business.com
|
||||
- messagerie.orange.fr
|
||||
- webmail.gandi.net
|
||||
- messagerie.sfr.fr
|
||||
- webmail.aliceadsl.fr
|
||||
- webmail.online.net
|
||||
- wmail.amen.fr
|
||||
- webmail.ovh.com
|
||||
|
@ -67,6 +69,10 @@
|
|||
- mon.service-public.fr
|
||||
- www.correspondants.cnil.fr
|
||||
- sso.quechoisir.org
|
||||
- connexion.mon.service-public.fr
|
||||
- mon.rsi.fr
|
||||
- jedeclare.com
|
||||
- net-entreprises.fr
|
||||
- description: Sites de commerce en ligne
|
||||
hostnames:
|
||||
- signin.ebay.fr
|
||||
|
|
|
@ -1,6 +1,59 @@
|
|||
require 'sslcheck/ssllabs/api'
|
||||
require 'erb'
|
||||
require 'logging'
|
||||
require 'parallel'
|
||||
require 'thread'
|
||||
|
||||
module SSLCheck
|
||||
module SSLLabs
|
||||
autoload :API, 'sslcheck/ssllabs/api'
|
||||
end
|
||||
autoload :Server, 'sslcheck/server'
|
||||
autoload :Grade, 'sslcheck/grade'
|
||||
|
||||
@@log = Logging.logger[SSLCheck]
|
||||
|
||||
def self.grade(hostname, port=443)
|
||||
timeout 600 do
|
||||
Grade.new Server.new hostname, port
|
||||
end
|
||||
rescue Exception => e
|
||||
@@log.error { "Error during #{hostname}:#{port} analysis : #{e}" }
|
||||
NoSslTlsGrade.new NoSslTlsServer.new hostname, port
|
||||
end
|
||||
|
||||
def self.analyze(hosts, output)
|
||||
results = {}
|
||||
semaphore = Mutex.new
|
||||
Parallel.each hosts, progress: 'Testing', in_threads: 10 do |description, host|
|
||||
result = SSLCheck.grade host.strip
|
||||
semaphore.synchronize do
|
||||
if results.include? description
|
||||
results[description] << result
|
||||
else
|
||||
results[description] = [result]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
results.each do |d, _|
|
||||
results[d].sort! do |a, b|
|
||||
cmp = score(a) <=> score(b)
|
||||
if cmp == 0
|
||||
cmp = a.score <=> b.score
|
||||
if cmp == 0
|
||||
cmp = a.server.hostname <=> b.server.hostname
|
||||
end
|
||||
end
|
||||
cmp
|
||||
end
|
||||
end
|
||||
|
||||
File.write "output/#{output}.html", ERB.new(File.read('output/sslcheck.erb')).result(binding)
|
||||
end
|
||||
|
||||
private
|
||||
SCORES = %w(A+ A A- B C D E F T M X)
|
||||
def self.score(a)
|
||||
SCORES.index a.grade
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
require 'timeout'
|
||||
|
||||
module SSLCheck
|
||||
class NoSslTlsGrade
|
||||
attr_reader :server, :score, :grade
|
||||
|
||||
def initialize(server)
|
||||
@server, @score, @grade = server, -1, 'X'
|
||||
end
|
||||
end
|
||||
|
||||
class Grade
|
||||
attr_reader :server, :score, :grade, :warning, :good
|
||||
attr_reader :server, :score, :grade, :warning, :success
|
||||
|
||||
def initialize(server)
|
||||
@server = server
|
||||
|
|
|
@ -5,12 +5,23 @@ require 'parallel'
|
|||
require 'tcp_timeout'
|
||||
|
||||
module SSLCheck
|
||||
class NoSslTlsServer
|
||||
attr_reader :hostname, :port
|
||||
|
||||
def initialize(hostname, port=443)
|
||||
@hostname, @port = hostname, port
|
||||
end
|
||||
end
|
||||
|
||||
class Server
|
||||
TCP_TIMEOUT = 60
|
||||
SSL_TIMEOUT = 2*TCP_TIMEOUT
|
||||
EXISTING_METHODS = %i(TLSv1_2 TLSv1_1 TLSv1 SSLv3 SSLv2)
|
||||
SUPPORTED_METHODS = OpenSSL::SSL::SSLContext::METHODS
|
||||
TIMEOUT = 5
|
||||
class TLSNotAvailableException < Exception; end
|
||||
class CipherNotAvailable < Exception; end
|
||||
class Timeout < Exception; end
|
||||
class ConnectionError < Exception; end
|
||||
|
||||
attr_reader :hostname, :port, :prefered_ciphers, :cert, :hsts
|
||||
|
||||
|
@ -19,12 +30,12 @@ module SSLCheck
|
|||
@hostname = hostname
|
||||
@port = port
|
||||
@methods = methods
|
||||
@log.error { "Check for #{hostname} (#{port})"}
|
||||
|
||||
@log.error { "Begin analysis" }
|
||||
extract_cert
|
||||
fetch_prefered_ciphers
|
||||
check_supported_cipher
|
||||
fetch_hsts
|
||||
@log.error { "End analysis" }
|
||||
end
|
||||
|
||||
def supported_methods
|
||||
|
@ -33,18 +44,32 @@ module SSLCheck
|
|||
{worst: worst, best: best}
|
||||
end
|
||||
|
||||
def key_size
|
||||
def key
|
||||
key = @cert.public_key
|
||||
case key
|
||||
when OpenSSL::PKey::RSA then
|
||||
key.n.num_bits
|
||||
[:rsa, key.n.num_bits]
|
||||
when OpenSSL::PKey::DSA then
|
||||
key.p.num_bits
|
||||
[:dsa, key.p.num_bits]
|
||||
when OpenSSL::PKey::EC then
|
||||
key.group.degree
|
||||
[:ecc, key.group.degree]
|
||||
end
|
||||
end
|
||||
|
||||
def key_size
|
||||
type, size = self.key
|
||||
if type == :ecc
|
||||
size = case size
|
||||
when 160 then 1024
|
||||
when 224 then 2048
|
||||
when 256 then 3072
|
||||
when 384 then 7680
|
||||
when 521 then 15360
|
||||
end
|
||||
end
|
||||
size
|
||||
end
|
||||
|
||||
def cipher_size
|
||||
cipher_strengths = supported_ciphers.collect { |c| c[2] }.uniq.sort
|
||||
worst, best = cipher_strengths.first, cipher_strengths.last
|
||||
|
@ -60,9 +85,9 @@ module SSLCheck
|
|||
end
|
||||
|
||||
{
|
||||
md2: %w(md2WithRSAEncryption),
|
||||
md5: %w(md5WithRSAEncryption md5WithRSA),
|
||||
sha1: %w(sha1WithRSAEncryption sha1WithRSA dsaWithSHA1 dsaWithSHA1_2 ecdsa_with_SHA1)
|
||||
md2: %w(md2WithRSAEncryption),
|
||||
md5: %w(md5WithRSAEncryption md5WithRSA),
|
||||
sha1: %w(sha1WithRSAEncryption sha1WithRSA dsaWithSHA1 dsaWithSHA1_2 ecdsa_with_SHA1)
|
||||
}.each do |name, signature|
|
||||
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
||||
def #{name}_sig?
|
||||
|
@ -72,12 +97,12 @@ module SSLCheck
|
|||
end
|
||||
|
||||
{
|
||||
md5: %w(MD5),
|
||||
sha1: %w(SHA),
|
||||
md5: %w(MD5),
|
||||
sha1: %w(SHA),
|
||||
|
||||
rc4: %w(RC4),
|
||||
des3: %w(3DES DES-CBC3),
|
||||
des: %w(DES-CBC)
|
||||
rc4: %w(RC4),
|
||||
des3: %w(3DES DES-CBC3),
|
||||
des: %w(DES-CBC)
|
||||
}.each do |name, ciphers|
|
||||
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
||||
def #{name}?
|
||||
|
@ -129,8 +154,52 @@ module SSLCheck
|
|||
end
|
||||
|
||||
private
|
||||
def ssl_client(method = nil, ciphers = nil, &block)
|
||||
ssl_context = method.nil? ? OpenSSL::SSL::SSLContext.new : OpenSSL::SSL::SSLContext.new(method)
|
||||
def connect(family, host, port, &block)
|
||||
socket = Socket.new family, Socket::SOCK_STREAM
|
||||
sockaddr = Socket.sockaddr_in port, host
|
||||
@log.debug { "Connecting to #{host}:#{port}" }
|
||||
begin
|
||||
status = socket.connect_nonblock sockaddr
|
||||
@log.debug { "Connecting to #{host}:#{port} status : #{status}" }
|
||||
raise ConnectionError.new status unless status == 0
|
||||
@log.debug { "Connected to #{host}:#{port}" }
|
||||
block_given? ? block.call(socket) : nil
|
||||
rescue IO::WaitReadable
|
||||
@log.debug { "Waiting for read to #{host}:#{port}" }
|
||||
raise Timeout.new unless IO.select [socket], nil, nil, TCP_TIMEOUT
|
||||
retry
|
||||
rescue IO::WaitWritable
|
||||
@log.debug { "Waiting for write to #{host}:#{port}" }
|
||||
raise Timeout.new unless IO.select nil, [socket], nil, TCP_TIMEOUT
|
||||
retry
|
||||
ensure
|
||||
socket.close
|
||||
end
|
||||
end
|
||||
|
||||
def ssl_connect(socket, context, method, &block)
|
||||
ssl_socket = OpenSSL::SSL::SSLSocket.new socket, context
|
||||
ssl_socket.hostname = @hostname unless method == :SSLv2
|
||||
@log.debug { "SSL connecting to #{@hostname}:#{@port}" }
|
||||
begin
|
||||
ssl_socket.connect_nonblock
|
||||
@log.debug { "SSL connected to #{@hostname}:#{@port}" }
|
||||
return block_given? ? block.call(ssl_socket) : nil
|
||||
rescue IO::WaitReadable
|
||||
@log.debug { "Waiting for SSL read to #{@hostname}:#{@port}" }
|
||||
raise Timeout.new unless IO.select [socket], nil, nil, SSL_TIMEOUT
|
||||
retry
|
||||
rescue IO::WaitWritable
|
||||
@log.debug { "Waiting for SSL write to #{@hostname}:#{@port}" }
|
||||
raise Timeout.new unless IO.select nil, [socket], nil, SSL_TIMEOUT
|
||||
retry
|
||||
ensure
|
||||
ssl_socket.close
|
||||
end
|
||||
end
|
||||
|
||||
def ssl_client(method, ciphers = nil, &block)
|
||||
ssl_context = OpenSSL::SSL::SSLContext.new method
|
||||
ssl_context.ciphers = ciphers if ciphers
|
||||
@log.debug { "Try #{method} connection with #{ciphers}" }
|
||||
|
||||
|
@ -144,47 +213,15 @@ module SSLCheck
|
|||
end
|
||||
|
||||
addrs.each do |addr|
|
||||
addr = addr[3]
|
||||
sockaddr = Socket.sockaddr_in @port, addr
|
||||
socket = Socket.new family, Socket::SOCK_STREAM
|
||||
begin
|
||||
@log.debug { "Connecting to #{addr}:#{@port}" }
|
||||
socket.connect_nonblock sockaddr
|
||||
rescue IO::WaitWritable
|
||||
@log.debug { "Waiting for connection to #{addr}:#{@port}" }
|
||||
if IO.select nil, [socket], nil, TIMEOUT
|
||||
begin
|
||||
if socket.connect_nonblock(sockaddr) == 0
|
||||
@log.debug { "Connected to #{addr}:#{@port}" }
|
||||
|
||||
ssl_socket = OpenSSL::SSL::SSLSocket.new socket, ssl_context
|
||||
ssl_socket.hostname = @hostname
|
||||
begin
|
||||
@log.debug { "TLS connection to #{addr}:#{@port}" }
|
||||
ssl_socket.connect
|
||||
return block_given? ? block.call(ssl_socket) : nil
|
||||
rescue OpenSSL::SSL::SSLError => e
|
||||
@log.debug { "Cipher not supported #{addr}:#{@port} : #{e}" }
|
||||
raise CipherNotAvailable.new e
|
||||
ensure
|
||||
@log.debug { "Closing TLS connection to #{addr}:#{@port}" }
|
||||
ssl_socket.close
|
||||
end
|
||||
end
|
||||
rescue Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH => e
|
||||
@log.debug { "Connection failure to #{addr}:#{@port} : #{e}" }
|
||||
end
|
||||
else
|
||||
@log.debug { "Connection timeout to #{addr}:#{@port}" }
|
||||
connect family, addr[3], @port do |socket|
|
||||
ssl_connect socket, ssl_context, method do |ssl_socket|
|
||||
return block_given? ? block.call(ssl_socket) : nil
|
||||
end
|
||||
ensure
|
||||
@log.debug { "Closing connection to #{addr}:#{@port}" }
|
||||
socket.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@log.debug { "No TLS available on #{@hostname}" }
|
||||
@log.debug { "No SSL available on #{@hostname}" }
|
||||
raise CipherNotAvailable.new
|
||||
end
|
||||
|
||||
|
@ -193,9 +230,10 @@ module SSLCheck
|
|||
next unless SUPPORTED_METHODS.include? method
|
||||
begin
|
||||
@cert = ssl_client(method) { |s| s.peer_cert }
|
||||
@log.warn { "Certificate #{@cert.subject}"}
|
||||
@log.warn { "Certificate #{@cert.subject}" }
|
||||
break
|
||||
rescue CipherNotAvailable
|
||||
rescue Exception => e
|
||||
@log.info { "Method #{method} not supported : #{e}" }
|
||||
end
|
||||
end
|
||||
raise TLSNotAvailableException.new unless @cert
|
||||
|
@ -203,10 +241,10 @@ module SSLCheck
|
|||
|
||||
def prefered_cipher(method)
|
||||
cipher = ssl_client(method, %w(ALL:COMPLEMENTOFALL)) { |s| s.cipher }
|
||||
@log.warn { "Prefered cipher for #{method} : #{cipher[0]}"}
|
||||
@log.warn { "Prefered cipher for #{method} : #{cipher[0]}" }
|
||||
cipher
|
||||
rescue CipherNotAvailable => e
|
||||
@log.info { "Method #{method} not supported : #{e}"}
|
||||
rescue Exception => e
|
||||
@log.info { "Method #{method} not supported : #{e}" }
|
||||
nil
|
||||
end
|
||||
|
||||
|
@ -216,6 +254,7 @@ module SSLCheck
|
|||
next unless SUPPORTED_METHODS.include? method
|
||||
@prefered_ciphers[method] = prefered_cipher method
|
||||
end
|
||||
raise TLSNotAvailableException.new unless @prefered_ciphers.any? { |_, c| !c.nil? }
|
||||
end
|
||||
|
||||
def available_ciphers(method)
|
||||
|
@ -224,10 +263,10 @@ module SSLCheck
|
|||
|
||||
def supported_cipher?(method, cipher)
|
||||
ssl_client method, [cipher]
|
||||
@log.warn { "Verify #{method} / #{cipher[0]} : OK"}
|
||||
@log.warn { "Verify #{method} / #{cipher[0]} : OK" }
|
||||
true
|
||||
rescue TLSNotAvailableException, CipherNotAvailable => e
|
||||
@log.debug { "Verify #{method} / #{cipher[0]} : NOK (#{e}"}
|
||||
rescue Exception => e
|
||||
@log.info { "Verify #{method} / #{cipher[0]} : NOK (#{e})" }
|
||||
false
|
||||
end
|
||||
|
||||
|
@ -247,10 +286,10 @@ module SSLCheck
|
|||
begin
|
||||
next unless SUPPORTED_METHODS.include? method
|
||||
@log.debug { "Check HSTS with #{method}" }
|
||||
response = HTTParty.head "https://#{@hostname}#{port}/", {follow_redirects: false, verify: false, ssl_version: method, timeout: TIMEOUT}
|
||||
response = HTTParty.head "https://#{@hostname}#{port}/", {follow_redirects: false, verify: false, ssl_version: method, timeout: SSL_TIMEOUT}
|
||||
break
|
||||
rescue
|
||||
@log.debug { "#{method} not supported" }
|
||||
rescue Exception => e
|
||||
@log.debug { "#{method} not supported : #{e}" }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -14,6 +14,15 @@
|
|||
td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.critical {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
td.critical:hover {
|
||||
background-color: #333 !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -28,21 +37,22 @@
|
|||
unless first
|
||||
%>
|
||||
<tr>
|
||||
<th colspan="16"> </th>
|
||||
<th colspan="17"> </th>
|
||||
</tr>
|
||||
<%
|
||||
end
|
||||
first = false
|
||||
%>
|
||||
<tr>
|
||||
<th colspan="16" id="<%= r[0] %>"><%= r[0] %></th>
|
||||
<th colspan="17" id="<%= r[0] %>"><%= r[0] %></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Site (IP)</th>
|
||||
<td>Rang</td>
|
||||
<td>Clef (bits)</td>
|
||||
<td>Chiff. (bits)</td>
|
||||
<td class="danger">SSL</td>
|
||||
<td class="danger">SSL v2</td>
|
||||
<td class="danger">SSL v3</td>
|
||||
<td class="success">TLS</td>
|
||||
<td class="success">TLS 1.2</td>
|
||||
<td class="success">TLS only</td>
|
||||
|
@ -57,12 +67,6 @@
|
|||
</tr>
|
||||
<% r[1].each do |n|
|
||||
s = n.server
|
||||
rank_color = case n.grade
|
||||
when 'A+' then :info
|
||||
when 'A', 'A-' then :success
|
||||
when 'B', 'C' then :warning
|
||||
else :danger
|
||||
end
|
||||
%>
|
||||
<tr>
|
||||
<th id="<%= s.hostname %>">
|
||||
|
@ -70,66 +74,85 @@
|
|||
<%= s.hostname %>
|
||||
</a>
|
||||
</th>
|
||||
<% if s.is_a? SSLCheck::NoSslTlsServer %>
|
||||
<td class="critical" colspan="16">
|
||||
No SSL/TLS
|
||||
</td>
|
||||
<%
|
||||
else
|
||||
rank_color = case n.grade
|
||||
when 'A+' then :info
|
||||
when 'A', 'A-' then :success
|
||||
when 'B', 'C' then :warning
|
||||
else :danger
|
||||
end
|
||||
%>
|
||||
<td class="<%= rank_color %>">
|
||||
<%= n.grade %>
|
||||
</td>
|
||||
<td class="<%= s.key_size < 2048 ? :danger : s.key_size < 4096 ? :warning : :success %>">
|
||||
<%= s.key_size %>
|
||||
(<%= s.key_size < 2048 ? '☹' : '☺' %>)
|
||||
<% type, size = s.key %>
|
||||
<%= "#{size} (#{type.to_s.upcase})" %>
|
||||
<span class="sr-only">(<%= s.key_size < 2048 ? '☹' : '☺' %>)</span>
|
||||
</td>
|
||||
<% cipher_size = s.cipher_size[:worst] %>
|
||||
<td class="<%= cipher_size < 112 ? :danger : cipher_size < 128 ? :warning : :success %>">
|
||||
<%= cipher_size %>
|
||||
(<%= cipher_size < 128 ? '☹' : '☺' %>)
|
||||
<span class="sr-only">(<%= cipher_size < 128 ? '☹' : '☺' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.ssl? ? :danger : :success %>">
|
||||
<%= s.ssl? ? '✓' : '✗' %>
|
||||
(<%= s.ssl? ? '☹' : '☺' %>)
|
||||
<td class="<%= s.sslv2? ? :danger : :success %>">
|
||||
<%= s.sslv2? ? '✓' : '✗' %>
|
||||
<span class="sr-only">(<%= s.sslv2? ? '☹' : '☺' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.sslv3? ? :danger : :success %>">
|
||||
<%= s.sslv3? ? '✓' : '✗' %>
|
||||
<span class="sr-only">(<%= s.sslv3? ? '☹' : '☺' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.tls? ? :success : :danger %>">
|
||||
<%= s.tls? ? '✓' : '✗' %>
|
||||
(<%= s.tls? ? '☺' : '☹' %>)
|
||||
<span class="sr-only">(<%= s.tls? ? '☺' : '☹' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.tlsv1_2? ? :success : :danger %>">
|
||||
<%= s.tlsv1_2? ? '✓' : '✗' %>
|
||||
(<%= s.tlsv1_2? ? '☺' : '☹' %>)
|
||||
<span class="sr-only">(<%= s.tlsv1_2? ? '☺' : '☹' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.tls_only? ? :success : :danger %>">
|
||||
<%= s.tls_only? ? '✓' : '✗' %>
|
||||
(<%= s.tls_only? ? '☺' : '☹' %>)
|
||||
<span class="sr-only">(<%= s.tls_only? ? '☺' : '☹' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.sha1_sig? ? :danger : :success %>">
|
||||
<%= s.sha1_sig? ? '✓' : '✗' %>
|
||||
(<%= s.sha1_sig? ? '☹' : '☺' %>)
|
||||
<span class="sr-only">(<%= s.sha1_sig? ? '☹' : '☺' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.rc4? ? :danger : :success %>">
|
||||
<%= s.rc4? ? '✓' : '✗' %>
|
||||
(<%= s.rc4? ? '☹' : '☺' %>)
|
||||
<span class="sr-only">(<%= s.rc4? ? '☹' : '☺' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.any_des? ? :danger : :success %>">
|
||||
<%= s.any_des? ? '✓' : '✗' %>
|
||||
(<%= s.any_des? ? '☹' : '☺' %>)
|
||||
<span class="sr-only">(<%= s.any_des? ? '☹' : '☺' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.md5? ? :danger : :success %>">
|
||||
<%= s.md5? ? '✓' : '✗' %>
|
||||
(<%= s.md5? ? '☹' : '☺' %>)
|
||||
<span class="sr-only">(<%= s.md5? ? '☹' : '☺' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.pfs? ? :success : :danger %>">
|
||||
<%= s.pfs? ? '✓' : '✗' %>
|
||||
(<%= s.pfs? ? '☺' : '☹' %>)
|
||||
<span class="sr-only">(<%= s.pfs? ? '☺' : '☹' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.pfs_only? ? :success : :danger %>">
|
||||
<%= s.pfs_only? ? '✓' : '✗' %>
|
||||
(<%= s.pfs_only? ? '☺' : '☹' %>)
|
||||
<span class="sr-only">(<%= s.pfs_only? ? '☺' : '☹' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.hsts? ? :success : :danger %>">
|
||||
<%= s.hsts? ? '✓' : '✗' %>
|
||||
(<%= s.hsts? ? '☺' : '☹' %>)
|
||||
<span class="sr-only">(<%= s.hsts? ? '☺' : '☹' %>)</span>
|
||||
</td>
|
||||
<td class="<%= s.hsts_long? ? :success : :danger %>">
|
||||
<%= s.hsts_long? ? '✓' : '✗' %>
|
||||
(<%= s.hsts_long? ? '☺' : '☹' %>)
|
||||
<span class="sr-only">(<%= s.hsts_long? ? '☺' : '☹' %>)</span>
|
||||
</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<% end %>
|
||||
<tr>
|
||||
|
@ -137,7 +160,8 @@
|
|||
<td>Rang</td>
|
||||
<td>Clef (bits)</td>
|
||||
<td>Chiff. (bits)</td>
|
||||
<td class="danger">SSL</td>
|
||||
<td class="danger">SSL v2</td>
|
||||
<td class="danger">SSL v3</td>
|
||||
<td class="success">TLS</td>
|
||||
<td class="success">TLS 1.2</td>
|
||||
<td class="success">TLS only</td>
|
|
@ -0,0 +1,10 @@
|
|||
--- Makefile 2014-12-13 01:20:15.025576957 +0100
|
||||
+++ Makefile 2014-12-13 01:26:44.801203932 +0100
|
||||
@@ -60,6 +60,7 @@
|
||||
sbindir = $(exec_prefix)/sbin
|
||||
bindir = $(exec_prefix)/bin
|
||||
archdir = $(rubyarchdir)
|
||||
+top_srcdir = ../..
|
||||
|
||||
|
||||
CC = gcc
|
8
sslcheck
8
sslcheck
|
@ -1,11 +1,11 @@
|
|||
#!/usr/bin/env ruby
|
||||
#ENV['LD_LIBRARY_PATH'] = '/home/aeris/Workspace/external/sslscan/openssl'
|
||||
ENV['LD_LIBRARY_PATH'] = '/home/aeris/Workspace/external/sslscan/openssl'
|
||||
require 'logging'
|
||||
$:.unshift 'lib'
|
||||
require 'sslcheck'
|
||||
|
||||
Logging.logger.root.appenders = Logging.appenders.stdout
|
||||
Logging.logger.root.level = :info
|
||||
Logging.logger.root.level = :warn
|
||||
|
||||
server = SSLCheck::Server.new ARGV[0]
|
||||
p SSLCheck::Grade.new server
|
||||
p server = SSLCheck::Server.new(ARGV[0])
|
||||
p grade = SSLCheck::Grade.new(server)
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env ruby
|
||||
require 'yaml'
|
||||
$:.unshift 'lib'
|
||||
require 'sslcheck'
|
||||
|
||||
Logging.logger.root.appenders = Logging.appenders.stdout
|
||||
Logging.logger.root.level = :error
|
||||
|
||||
hosts = []
|
||||
File.open('top-1m.csv', 'r') do |file|
|
||||
i = 0
|
||||
while line = file.gets
|
||||
hosts << ['Top 100 Alexa', line.strip.split(',')[1]]
|
||||
i += 1
|
||||
break if i == 100
|
||||
end
|
||||
end
|
||||
|
||||
SSLCheck.analyze hosts, 'alexa'
|
62
sslcheck-all
62
sslcheck-all
|
@ -1,66 +1,16 @@
|
|||
#!/usr/bin/env ruby
|
||||
require 'erb'
|
||||
require 'yaml'
|
||||
require 'thread'
|
||||
require 'parallel'
|
||||
require 'logging'
|
||||
$:.unshift 'lib'
|
||||
require 'sslcheck'
|
||||
|
||||
#Logging.logger.root.appenders = Logging.appenders.stdout
|
||||
#Logging.logger.root.level = :info
|
||||
|
||||
SCORES = %w(A+ A A- B C D E F T M)
|
||||
def score(a); SCORES.index a.grade; end
|
||||
|
||||
def check(hostname)
|
||||
hostname.strip!
|
||||
#print ' ', hostname, ' : '
|
||||
begin
|
||||
server = SSLCheck::Server.new hostname
|
||||
note = SSLCheck::Grade.new server
|
||||
#puts note.grade
|
||||
note
|
||||
rescue => e
|
||||
puts e
|
||||
raise
|
||||
end
|
||||
end
|
||||
Logging.logger.root.appenders = Logging.appenders.stdout
|
||||
Logging.logger.root.level = :error
|
||||
|
||||
config = YAML.load_file 'hosts.yml'
|
||||
results = Hash[config.collect { |c| [c['description'], []] }]
|
||||
|
||||
|
||||
tests = []
|
||||
hosts = []
|
||||
config.each do |c|
|
||||
description, hosts = c['description'], c['hostnames']
|
||||
hosts.each { |host| tests << [description, host] }
|
||||
d, hs = c['description'], c['hostnames']
|
||||
hs.each { |host| hosts << [d, host] }
|
||||
end
|
||||
|
||||
# tests.each do |description, host|
|
||||
# results[description] << check(host)
|
||||
# end
|
||||
|
||||
semaphore = Mutex.new
|
||||
Parallel.each tests, progress: 'Testing', in_threads: 8 do |description, host|
|
||||
begin
|
||||
result = check host
|
||||
semaphore.synchronize do
|
||||
results[description] << result
|
||||
end
|
||||
rescue SSLCheck::Server::TLSNotAvailableException
|
||||
rescue Exception => e
|
||||
p host, e
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
results.each do |d, _|
|
||||
results[d].sort! do |a, b|
|
||||
cmp = score(a) <=> score(b)
|
||||
cmp != 0 ? cmp : a.server.hostname <=> b.server.hostname
|
||||
end
|
||||
end
|
||||
|
||||
puts 'Generate results'
|
||||
File.write 'output/index.html', ERB.new(File.read('index2.erb')).result(binding)
|
||||
SSLCheck.analyze hosts, 'results'
|
||||
|
|
79
test.rb
79
test.rb
|
@ -1,79 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
#ENV['LD_LIBRARY_PATH'] = '/home/aeris/Workspace/external/sslscan/openssl'
|
||||
require 'logging'
|
||||
$:.unshift 'lib'
|
||||
require 'sslcheck'
|
||||
|
||||
Logging.logger.root.appenders = Logging.appenders.stdout
|
||||
Logging.logger.root.level = :debug
|
||||
|
||||
# Server = Class.new SSLCheck::Server do
|
||||
# def initialize
|
||||
# @key = OpenSSL::PKey::RSA.new 2048
|
||||
# name = OpenSSL::X509::Name.parse 'CN=nobody/DC=example'
|
||||
# @cert = OpenSSL::X509::Certificate.new
|
||||
# @cert.version = 3
|
||||
# @cert.serial = 0
|
||||
# @cert.not_before = Time.now
|
||||
# @cert.not_after = Time.now + 3600
|
||||
# @cert.public_key = @key.public_key
|
||||
# @cert.subject = name
|
||||
#
|
||||
# @supported_ciphers =
|
||||
# {SSLv3: [], TLSv1: [['ECDHE-RSA-AES256-SHA', 'TLSv1/SSLv3', 256, 256], ['DHE-RSA-AES256-SHA', 'TLSv1/SSLv3', 256, 256], ['ECDHE-RSA-AES128-SHA', 'TLSv1/SSLv3', 128, 128], ['DHE-RSA-AES128-SHA', 'TLSv1/SSLv3', 128, 128]], TLSv1_1: [['ECDHE-RSA-AES256-SHA', 'TLSv1/SSLv3', 256, 256], ['DHE-RSA-AES256-SHA', 'TLSv1/SSLv3', 256, 256], ['ECDHE-RSA-AES128-SHA', 'TLSv1/SSLv3', 128, 128], ['DHE-RSA-AES128-SHA', 'TLSv1/SSLv3', 128, 128]], TLSv1_2: [['ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1/SSLv3', 256, 256], ['ECDHE-RSA-AES256-SHA384', 'TLSv1/SSLv3', 256, 256], ['ECDHE-RSA-AES256-SHA', 'TLSv1/SSLv3', 256, 256], ['DHE-RSA-AES256-GCM-SHA384', 'TLSv1/SSLv3', 256, 256], ['DHE-RSA-AES256-SHA256', 'TLSv1/SSLv3', 256, 256], ['DHE-RSA-AES256-SHA', 'TLSv1/SSLv3', 256, 256], ['ECDHE-RSA-AES128-GCM-SHA256', 'TLSv1/SSLv3', 128, 128], ['ECDHE-RSA-AES128-SHA256', 'TLSv1/SSLv3', 128, 128], ['ECDHE-RSA-AES128-SHA', 'TLSv1/SSLv3', 128, 128], ['DHE-RSA-AES128-GCM-SHA256', 'TLSv1/SSLv3', 128, 128], ['DHE-RSA-AES128-SHA256', 'TLSv1/SSLv3', 128, 128], ['DHE-RSA-AES128-SHA', 'TLSv1/SSLv3', 128, 128]]}
|
||||
# @prefered_ciphers = {SSLv3: nil, TLSv1: ['ECDHE-RSA-AES128-SHA', 'TLSv1/SSLv3', 128, 128], TLSv1_1: ['ECDHE-RSA-AES128-SHA', 'TLSv1/SSLv3', 128, 128], TLSv1_2: ['ECDHE-RSA-AES128-GCM-SHA256', 'TLSv1/SSLv3', 128, 128]}
|
||||
#
|
||||
# @hsts = 31536000
|
||||
# end
|
||||
# end
|
||||
#server = Server.new
|
||||
#server = SSLCheck::Server.new 'www.cjn.justice.gouv.fr'
|
||||
#server = SSLCheck::Server.new 'www.capitainetrain.com'
|
||||
server = SSLCheck::Server.new 'matlink.fr'
|
||||
p SSLCheck::Grade.new server
|
||||
exit
|
||||
|
||||
hostname, port = ['www.cjn.justice.gouv.fr', 443]
|
||||
tcp_client = TCPSocket.new hostname, port
|
||||
ssl_client = OpenSSL::SSL::SSLSocket.new tcp_client
|
||||
ssl_client.hostname = hostname
|
||||
p ssl_client.connect
|
||||
|
||||
|
||||
#hostname = 'provaping.com'
|
||||
#compressions = {}
|
||||
# existing_methods.each do |method|
|
||||
# next unless supported_methods.include? method
|
||||
# socket_context = OpenSSL::SSL::SSLContext.new method
|
||||
# socket_context.ciphers = %w(ALL:COMPLEMENTOFALL)
|
||||
# tcp_client = TCPSocket.new hostname, port
|
||||
# ssl_client = OpenSSL::SSL::SSLSocket.new tcp_client, socket_context
|
||||
# ssl_client.hostname = hostname
|
||||
# begin
|
||||
# ssl = ssl_client.connect
|
||||
# data = OpenSSL::ASN1.decode(ssl.session.to_der).value.find { |a| a.tag == 11 }
|
||||
# compression = !data.nil?
|
||||
# compressions[method] = compression
|
||||
# rescue OpenSSL::SSL::SSLError => e
|
||||
# end
|
||||
# end
|
||||
#p "Compressions", compressions
|
||||
|
||||
#hostname = 'espaceclient.groupama.fr' # not supported
|
||||
# hostname = 'ameli.moncompte.mobi'
|
||||
# renegociations = {}
|
||||
# existing_methods.each do |method|
|
||||
# next unless supported_methods.include? method
|
||||
# socket_context = OpenSSL::SSL::SSLContext.new method
|
||||
# socket_context.ciphers = %w(ALL:COMPLEMENTOFALL)
|
||||
# tcp_client = TCPSocket.new hostname, port
|
||||
# ssl_client = OpenSSL::SSL::SSLSocket.new tcp_client, socket_context
|
||||
# ssl_client.hostname = hostname
|
||||
# begin
|
||||
# ssl = ssl_client.connect
|
||||
# p ssl
|
||||
# #data = OpenSSL::ASN1.decode(ssl.session.to_der).value.find { |a| a.tag == 11 }
|
||||
# rescue OpenSSL::SSL::SSLError => e
|
||||
# end
|
||||
# end
|
||||
# p "Renegociations", renegociations
|
Loading…
Reference in New Issue