ssl_labs 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +13 -0
- data/Rakefile +26 -0
- data/lib/ssl_labs/api.rb +34 -0
- data/lib/ssl_labs/endpoint.rb +46 -0
- data/lib/ssl_labs/endpoint_data/details/cert.rb +63 -0
- data/lib/ssl_labs/endpoint_data/details/chain.rb +40 -0
- data/lib/ssl_labs/endpoint_data/details/key.rb +40 -0
- data/lib/ssl_labs/endpoint_data/details/protocol.rb +38 -0
- data/lib/ssl_labs/endpoint_data/details/sim/client.rb +43 -0
- data/lib/ssl_labs/endpoint_data/details/sim.rb +43 -0
- data/lib/ssl_labs/endpoint_data/details/suite.rb +43 -0
- data/lib/ssl_labs/endpoint_data/details.rb +77 -0
- data/lib/ssl_labs/endpoint_data.rb +49 -0
- data/lib/ssl_labs/host.rb +58 -0
- data/lib/ssl_labs/info.rb +41 -0
- data/lib/ssl_labs/util.rb +22 -0
- data/lib/ssl_labs.rb +93 -0
- data/test/endpoint_data.json +153 -0
- data/test/test_endpoint_data.rb +17 -0
- metadata +93 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 757eafa88db5476feb6a61d68a5cf7fe7ca31433
|
4
|
+
data.tar.gz: 367750793ad3ed2d792145c511b536a81144388c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: da209d49df109bbf639114dbaaa396eb2ad51d538655b77119c7e3361281924d90e807c06679d91b388803a1aeae8b373ce8330b63937bd6aa791a9b127ca0eb
|
7
|
+
data.tar.gz: 1cc4c8e4429aff72b64e1c65276e370db2db5026cbf33cbe671e869e046de81c2ee1d092cfb80f137a700d81aeed9da162830d04eafb085ef28ea3ab5d64b769
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'rubygems/package_task'
|
6
|
+
|
7
|
+
desc 'Default task (package)'
|
8
|
+
task :default => [:package]
|
9
|
+
|
10
|
+
Rake::TestTask.new('test')
|
11
|
+
|
12
|
+
SPECFILE = 'ssl_labs.gemspec'
|
13
|
+
if File.exist?(SPECFILE)
|
14
|
+
spec = eval(File.read(SPECFILE))
|
15
|
+
Gem::PackageTask.new(spec).define
|
16
|
+
end
|
17
|
+
|
18
|
+
RDoc::Task.new do |rdoc|
|
19
|
+
rdoc.rdoc_dir = 'rdoc'
|
20
|
+
rdoc.title = 'ssl_labs'
|
21
|
+
rdoc.options << '--charset' << 'utf-8'
|
22
|
+
rdoc.options << '--all'
|
23
|
+
rdoc.rdoc_files.include('README.md')
|
24
|
+
rdoc.rdoc_files.include(FileList['lib/**/*'])
|
25
|
+
rdoc.rdoc_files.include(FileList['test/**/*'])
|
26
|
+
end
|
data/lib/ssl_labs/api.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'ssl_labs/util'
|
2
|
+
|
3
|
+
class SslLabs
|
4
|
+
|
5
|
+
module Api
|
6
|
+
|
7
|
+
# Base URI for the API.
|
8
|
+
LOCATION = 'https://api.dev.ssllabs.com/api/fa78d5a4'
|
9
|
+
|
10
|
+
# Array of known methods.
|
11
|
+
METHODS = [
|
12
|
+
:analyze,
|
13
|
+
:get_endpoint_data,
|
14
|
+
:get_status_codes,
|
15
|
+
:info
|
16
|
+
]
|
17
|
+
|
18
|
+
# Return the API URL for the given method and arguments.
|
19
|
+
def self.url(method, args={})
|
20
|
+
raise ArgumentError, "Unknown method #{method.inspect}" unless METHODS.include?(method)
|
21
|
+
camelized_method = Util::camelize(method)
|
22
|
+
query = if args.empty?
|
23
|
+
''
|
24
|
+
else
|
25
|
+
'?' << args.map do |k, v|
|
26
|
+
"#{Util.camelize(k)}=#{v}"
|
27
|
+
end.join('&') # XXX escaping
|
28
|
+
end
|
29
|
+
"#{LOCATION}/#{camelized_method}#{query}"
|
30
|
+
end
|
31
|
+
|
32
|
+
end # Api
|
33
|
+
|
34
|
+
end # SslLabs
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'ssl_labs/util'
|
5
|
+
|
6
|
+
class SslLabs
|
7
|
+
|
8
|
+
class Endpoint
|
9
|
+
|
10
|
+
ATTRS = [
|
11
|
+
:delegation,
|
12
|
+
:duration,
|
13
|
+
:eta,
|
14
|
+
:grade,
|
15
|
+
:has_warnings,
|
16
|
+
:ip_address,
|
17
|
+
:is_exceptional,
|
18
|
+
:progress,
|
19
|
+
:server_name,
|
20
|
+
:status_details,
|
21
|
+
:status_details_message,
|
22
|
+
:status_message
|
23
|
+
]
|
24
|
+
|
25
|
+
attr_accessor(*ATTRS)
|
26
|
+
|
27
|
+
def self.from_hash(hash)
|
28
|
+
endpoint = self.new
|
29
|
+
hash.each do |k, v|
|
30
|
+
sym = Util.underscore(k).to_sym
|
31
|
+
if ATTRS.include?(sym)
|
32
|
+
if sym == :ip_address
|
33
|
+
endpoint.ip_address = IPAddr.new(v)
|
34
|
+
else
|
35
|
+
endpoint.send("#{sym}=", v)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
raise ArgumentError, "Unknown key #{k.inspect} (#{sym})"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
endpoint
|
42
|
+
end
|
43
|
+
|
44
|
+
end # Endpoint
|
45
|
+
|
46
|
+
end # SslLabs
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'ssl_labs/util'
|
2
|
+
|
3
|
+
class SslLabs
|
4
|
+
|
5
|
+
class EndpointData
|
6
|
+
|
7
|
+
class Details
|
8
|
+
|
9
|
+
class Cert
|
10
|
+
|
11
|
+
ATTRS = [
|
12
|
+
:alt_names,
|
13
|
+
:common_names,
|
14
|
+
:crl_uris,
|
15
|
+
:issuer_label,
|
16
|
+
:issuer_subject,
|
17
|
+
:issues,
|
18
|
+
:label,
|
19
|
+
:not_after,
|
20
|
+
:not_before,
|
21
|
+
:ocsp_uris,
|
22
|
+
:raw,
|
23
|
+
:revocation_info,
|
24
|
+
:revocation_status,
|
25
|
+
:sgc,
|
26
|
+
:sig_alg,
|
27
|
+
:subject,
|
28
|
+
:validation_type
|
29
|
+
]
|
30
|
+
|
31
|
+
attr_accessor(*ATTRS)
|
32
|
+
|
33
|
+
def self.from_hash(hash)
|
34
|
+
cert = self.new
|
35
|
+
hash.each do |k, v|
|
36
|
+
sym = Util.underscore(k).to_sym
|
37
|
+
case sym
|
38
|
+
when :crl_ur_is
|
39
|
+
cert.crl_uris = v
|
40
|
+
when :not_after
|
41
|
+
cert.not_after = Time.at(v / 1000.0)
|
42
|
+
when :not_before
|
43
|
+
cert.not_before = Time.at(v / 1000.0)
|
44
|
+
when :ocsp_ur_is
|
45
|
+
cert.ocsp_uris = v
|
46
|
+
when :scg
|
47
|
+
cert.sgc = v
|
48
|
+
when *ATTRS
|
49
|
+
cert.send("#{sym}=", v)
|
50
|
+
else
|
51
|
+
raise ArgumentError, "Unknown key #{k.inspect} (#{sym.inspect})"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
cert
|
55
|
+
end
|
56
|
+
|
57
|
+
end # Cert
|
58
|
+
|
59
|
+
end # Details
|
60
|
+
|
61
|
+
end # EndpointData
|
62
|
+
|
63
|
+
end # SslLabs
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'ssl_labs/endpoint_data/details/cert'
|
2
|
+
|
3
|
+
class SslLabs
|
4
|
+
|
5
|
+
class EndpointData
|
6
|
+
|
7
|
+
class Details
|
8
|
+
|
9
|
+
class Chain
|
10
|
+
|
11
|
+
ATTRS = [
|
12
|
+
:certs,
|
13
|
+
:issues
|
14
|
+
]
|
15
|
+
|
16
|
+
attr_accessor(*ATTRS)
|
17
|
+
|
18
|
+
def self.from_hash(hash)
|
19
|
+
chain = self.new
|
20
|
+
hash.each do |k, v|
|
21
|
+
sym = Util.underscore(k).to_sym
|
22
|
+
case sym
|
23
|
+
when :certs
|
24
|
+
chain.certs = v.map { |cert| Cert.from_hash(cert) }
|
25
|
+
when *ATTRS
|
26
|
+
chain.send("#{sym}=", v)
|
27
|
+
else
|
28
|
+
raise ArgumentError, "Unknown key #{k.inspect} (#{sym.inspect})"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
chain
|
32
|
+
end
|
33
|
+
|
34
|
+
end # Chain
|
35
|
+
|
36
|
+
end # Details
|
37
|
+
|
38
|
+
end # EndpointData
|
39
|
+
|
40
|
+
end # SslLabs
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'ssl_labs/util'
|
2
|
+
|
3
|
+
class SslLabs
|
4
|
+
|
5
|
+
class EndpointData
|
6
|
+
|
7
|
+
class Details
|
8
|
+
|
9
|
+
class Key
|
10
|
+
|
11
|
+
ATTRS = [
|
12
|
+
:size,
|
13
|
+
:strength,
|
14
|
+
:alg,
|
15
|
+
:debian_flaw,
|
16
|
+
:q
|
17
|
+
]
|
18
|
+
|
19
|
+
attr_accessor(*ATTRS)
|
20
|
+
|
21
|
+
def self.from_hash(hash)
|
22
|
+
key = self.new
|
23
|
+
hash.each do |k, v|
|
24
|
+
sym = Util.underscore(k).to_sym
|
25
|
+
if ATTRS.include?(sym)
|
26
|
+
key.send("#{sym}=", v)
|
27
|
+
else
|
28
|
+
raise ArgumentError, "Unknown key #{k.inspect} (#{sym.inspect})"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
key
|
32
|
+
end
|
33
|
+
|
34
|
+
end # Key
|
35
|
+
|
36
|
+
end # Details
|
37
|
+
|
38
|
+
end # EndpointData
|
39
|
+
|
40
|
+
end # SslLabs
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'ssl_labs/util'
|
2
|
+
|
3
|
+
class SslLabs
|
4
|
+
|
5
|
+
class EndpointData
|
6
|
+
|
7
|
+
class Details
|
8
|
+
|
9
|
+
class Protocol
|
10
|
+
|
11
|
+
ATTRS = [
|
12
|
+
:id,
|
13
|
+
:name,
|
14
|
+
:version
|
15
|
+
]
|
16
|
+
|
17
|
+
attr_accessor(*ATTRS)
|
18
|
+
|
19
|
+
def self.from_hash(hash)
|
20
|
+
protocol = self.new
|
21
|
+
hash.each do |k, v|
|
22
|
+
sym = Util.underscore(k).to_sym
|
23
|
+
if ATTRS.include?(sym)
|
24
|
+
protocol.send("#{sym}=", v)
|
25
|
+
else
|
26
|
+
raise ArgumentError, "Unknown key #{k.inspect} (#{sym.inspect})"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
protocol
|
30
|
+
end
|
31
|
+
|
32
|
+
end # Protocol
|
33
|
+
|
34
|
+
end # Details
|
35
|
+
|
36
|
+
end # EndpointData
|
37
|
+
|
38
|
+
end # SslLabs
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'ssl_labs/util'
|
2
|
+
|
3
|
+
class SslLabs
|
4
|
+
|
5
|
+
class EndpointData
|
6
|
+
|
7
|
+
class Details
|
8
|
+
|
9
|
+
class Sim
|
10
|
+
|
11
|
+
class Client
|
12
|
+
|
13
|
+
ATTRS = [
|
14
|
+
:id,
|
15
|
+
:name,
|
16
|
+
:platform,
|
17
|
+
:version,
|
18
|
+
:is_reference
|
19
|
+
]
|
20
|
+
attr_accessor(*ATTRS)
|
21
|
+
|
22
|
+
def self.from_hash(hash)
|
23
|
+
client = self.new
|
24
|
+
hash.each do |k, v|
|
25
|
+
sym = Util.underscore(k).to_sym
|
26
|
+
if ATTRS.include?(sym)
|
27
|
+
client.send("#{sym}=", v)
|
28
|
+
else
|
29
|
+
raise ArgumentError, "Unknown key #{k.inspect} (#{sym.inspect})"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
client
|
33
|
+
end
|
34
|
+
|
35
|
+
end # Client
|
36
|
+
|
37
|
+
end # Sim
|
38
|
+
|
39
|
+
end # Details
|
40
|
+
|
41
|
+
end # EndpointData
|
42
|
+
|
43
|
+
end # SslLabs
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'ssl_labs/endpoint_data/details/sim/client'
|
2
|
+
require 'ssl_labs/util'
|
3
|
+
|
4
|
+
class SslLabs
|
5
|
+
|
6
|
+
class EndpointData
|
7
|
+
|
8
|
+
class Details
|
9
|
+
|
10
|
+
class Sim
|
11
|
+
|
12
|
+
ATTRS = [
|
13
|
+
:client,
|
14
|
+
:error_code,
|
15
|
+
:attempts,
|
16
|
+
:protocol_id,
|
17
|
+
:suite_id
|
18
|
+
]
|
19
|
+
|
20
|
+
attr_accessor(*ATTRS)
|
21
|
+
|
22
|
+
def self.from_hash(hash)
|
23
|
+
sim = self.new
|
24
|
+
hash.each do |k, v|
|
25
|
+
sym = Util.underscore(k).to_sym
|
26
|
+
if sym == :client
|
27
|
+
sim.client = Sim::Client.from_hash(v)
|
28
|
+
elsif ATTRS.include?(sym)
|
29
|
+
sim.send("#{sym}=", v)
|
30
|
+
else
|
31
|
+
raise ArgumentError, "Unknown key #{k.inspect} (#{sym.inspect})"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
sim
|
35
|
+
end
|
36
|
+
|
37
|
+
end # Sim
|
38
|
+
|
39
|
+
end # Details
|
40
|
+
|
41
|
+
end # EndpointData
|
42
|
+
|
43
|
+
end # SslLabs
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'ssl_labs/util'
|
2
|
+
|
3
|
+
class SslLabs
|
4
|
+
|
5
|
+
class EndpointData
|
6
|
+
|
7
|
+
class Details
|
8
|
+
|
9
|
+
class Suite
|
10
|
+
|
11
|
+
ATTRS = [
|
12
|
+
:id,
|
13
|
+
:name,
|
14
|
+
:cipher_strength,
|
15
|
+
:dh_strength,
|
16
|
+
:dh_p,
|
17
|
+
:dh_g,
|
18
|
+
:dh_ys,
|
19
|
+
:q
|
20
|
+
]
|
21
|
+
|
22
|
+
attr_accessor(*ATTRS)
|
23
|
+
|
24
|
+
def self.from_hash(hash)
|
25
|
+
suite = self.new
|
26
|
+
hash.each do |k, v|
|
27
|
+
sym = Util.underscore(k).to_sym
|
28
|
+
if ATTRS.include?(sym)
|
29
|
+
suite.send("#{sym}=", v)
|
30
|
+
else
|
31
|
+
raise ArgumentError, "Unknown key #{k.inspect} (#{sym.inspect})"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
suite
|
35
|
+
end
|
36
|
+
|
37
|
+
end # Suite
|
38
|
+
|
39
|
+
end # Details
|
40
|
+
|
41
|
+
end # EndpointData
|
42
|
+
|
43
|
+
end # SslLabs
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'ssl_labs/endpoint_data/details/cert'
|
2
|
+
require 'ssl_labs/endpoint_data/details/chain'
|
3
|
+
require 'ssl_labs/endpoint_data/details/key'
|
4
|
+
require 'ssl_labs/endpoint_data/details/protocol'
|
5
|
+
require 'ssl_labs/endpoint_data/details/suite'
|
6
|
+
require 'ssl_labs/endpoint_data/details/sim'
|
7
|
+
require 'ssl_labs/util'
|
8
|
+
|
9
|
+
class SslLabs
|
10
|
+
|
11
|
+
class EndpointData
|
12
|
+
|
13
|
+
class Details
|
14
|
+
|
15
|
+
ATTRS = [
|
16
|
+
:cert,
|
17
|
+
:chain,
|
18
|
+
:compression_methods,
|
19
|
+
:host_start_time,
|
20
|
+
:key,
|
21
|
+
:non_prefix_delegation,
|
22
|
+
:prefix_delegation,
|
23
|
+
:protocols,
|
24
|
+
:reneg_support,
|
25
|
+
:server_signature,
|
26
|
+
:session_resumption,
|
27
|
+
:suites,
|
28
|
+
:vuln_beast,
|
29
|
+
:heartbleed,
|
30
|
+
:heartbeat,
|
31
|
+
:open_ssl_ccs,
|
32
|
+
:session_tickets,
|
33
|
+
:sni_required,
|
34
|
+
:ocsp_stapling,
|
35
|
+
:supports_npn,
|
36
|
+
:supports_rc4,
|
37
|
+
:forward_secrecy,
|
38
|
+
:rc4_with_modern,
|
39
|
+
:http_status_code,
|
40
|
+
:sims
|
41
|
+
]
|
42
|
+
|
43
|
+
attr_accessor(*ATTRS)
|
44
|
+
|
45
|
+
def self.from_hash(hash)
|
46
|
+
details = self.new
|
47
|
+
hash.each do |k, v|
|
48
|
+
sym = Util.underscore(k).to_sym
|
49
|
+
case sym
|
50
|
+
when :cert
|
51
|
+
details.cert = Cert.from_hash(v)
|
52
|
+
when :chain
|
53
|
+
details.chain = Chain.from_hash(v)
|
54
|
+
when :host_start_time
|
55
|
+
details.host_start_time = Time.at(v / 1000.0)
|
56
|
+
when :key
|
57
|
+
details.key = Key.from_hash(v)
|
58
|
+
when :protocols
|
59
|
+
details.protocols = v['list'].map { |hash| Protocol.from_hash(hash) }
|
60
|
+
when :sims
|
61
|
+
details.sims = v['results'].map { |hash| Sim.from_hash(hash) }
|
62
|
+
when :suites
|
63
|
+
details.suites = v['list'].map { |hash| Suite.from_hash(hash) }
|
64
|
+
when *ATTRS
|
65
|
+
details.send("#{sym}=", v)
|
66
|
+
else
|
67
|
+
raise ArgumentError, "Unknown key #{k.inspect} (#{sym.inspect})"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
details
|
71
|
+
end
|
72
|
+
|
73
|
+
end # Details
|
74
|
+
|
75
|
+
end # EndpointData
|
76
|
+
|
77
|
+
end # SslLabs
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'ssl_labs/util'
|
5
|
+
require 'ssl_labs/endpoint_data/details'
|
6
|
+
|
7
|
+
class SslLabs
|
8
|
+
|
9
|
+
class EndpointData
|
10
|
+
|
11
|
+
ATTRS = [
|
12
|
+
:delegation,
|
13
|
+
:details,
|
14
|
+
:duration,
|
15
|
+
:eta,
|
16
|
+
:grade,
|
17
|
+
:has_warnings,
|
18
|
+
:ip_address,
|
19
|
+
:is_exceptional,
|
20
|
+
:progress,
|
21
|
+
:server_name,
|
22
|
+
:status_message
|
23
|
+
]
|
24
|
+
|
25
|
+
attr_accessor(*ATTRS)
|
26
|
+
|
27
|
+
def self.from_hash(hash)
|
28
|
+
endpoint = self.new
|
29
|
+
hash.each do |k, v|
|
30
|
+
sym = Util.underscore(k).to_sym
|
31
|
+
if ATTRS.include?(sym)
|
32
|
+
case sym
|
33
|
+
when :ip_address
|
34
|
+
endpoint.ip_address = IPAddr.new(v)
|
35
|
+
when :details
|
36
|
+
endpoint.details = EndpointData::Details.from_hash(v)
|
37
|
+
else
|
38
|
+
endpoint.send("#{sym}=", v)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
raise ArgumentError, "Unknown key #{k.inspect} (#{sym})"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
endpoint
|
45
|
+
end
|
46
|
+
|
47
|
+
end # EndpointData
|
48
|
+
|
49
|
+
end # SslLabs
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'ssl_labs/endpoint'
|
2
|
+
require 'ssl_labs/util'
|
3
|
+
|
4
|
+
class SslLabs
|
5
|
+
|
6
|
+
class Host
|
7
|
+
|
8
|
+
ATTRS = [
|
9
|
+
:criteria_version,
|
10
|
+
:delegation,
|
11
|
+
:duration,
|
12
|
+
:endpoints,
|
13
|
+
:engine_version,
|
14
|
+
:eta,
|
15
|
+
:grade,
|
16
|
+
:has_warnings,
|
17
|
+
:host,
|
18
|
+
:is_exceptional,
|
19
|
+
:is_public,
|
20
|
+
:port,
|
21
|
+
:progress,
|
22
|
+
:protocol,
|
23
|
+
:start_time,
|
24
|
+
:status,
|
25
|
+
:status_message,
|
26
|
+
:test_time
|
27
|
+
]
|
28
|
+
|
29
|
+
attr_accessor(*ATTRS)
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
@endpoints = []
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.from_json(str)
|
36
|
+
json = JSON.parse(str)
|
37
|
+
host = self.new
|
38
|
+
json.each do |k, v|
|
39
|
+
sym = Util.underscore(k).to_sym
|
40
|
+
if ATTRS.include?(sym)
|
41
|
+
case sym
|
42
|
+
when :start_time
|
43
|
+
host.start_time = Time.at(v / 1000.0)
|
44
|
+
when :endpoints
|
45
|
+
host.endpoints += v.map { |ep| Endpoint.from_hash(ep) }
|
46
|
+
else
|
47
|
+
host.send("#{sym}=", v)
|
48
|
+
end
|
49
|
+
else
|
50
|
+
raise ArgumentError, "Unknown JSON key #{k.inspect} (#{sym.inspect})"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
host
|
54
|
+
end
|
55
|
+
|
56
|
+
end # Host
|
57
|
+
|
58
|
+
end # SslLabs
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class SslLabs
|
4
|
+
|
5
|
+
class Info
|
6
|
+
|
7
|
+
ATTRS = [
|
8
|
+
:engine_version,
|
9
|
+
:criteria_version,
|
10
|
+
:client_max_assessments
|
11
|
+
]
|
12
|
+
|
13
|
+
attr_accessor(*ATTRS)
|
14
|
+
|
15
|
+
# Create an Info from a JSON object.
|
16
|
+
def self.from_json(str)
|
17
|
+
json = JSON.parse(str)
|
18
|
+
info = self.new
|
19
|
+
json.each do |k, v|
|
20
|
+
case k
|
21
|
+
when 'engineVersion'
|
22
|
+
info.engine_version = v
|
23
|
+
when 'criteriaVersion'
|
24
|
+
info.criteria_version = v
|
25
|
+
when 'clientMaxAssessments'
|
26
|
+
info.client_max_assessments = v.to_i
|
27
|
+
else
|
28
|
+
raise ArgumentError, "Unknown key #{k.inspect}"
|
29
|
+
end
|
30
|
+
info
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Convert an Info to a Hash.
|
35
|
+
def to_hash
|
36
|
+
Hash[*ATTRS.map { |attr| [attr, self.send(attr)] }]
|
37
|
+
end
|
38
|
+
|
39
|
+
end # Info
|
40
|
+
|
41
|
+
end # SslLabs
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
|
3
|
+
class SslLabs
|
4
|
+
|
5
|
+
# Utility methods.
|
6
|
+
module Util
|
7
|
+
|
8
|
+
# Camelizes a snake case method or argument name.
|
9
|
+
# For example "get_status_codes" -> GetStatusCodes'.
|
10
|
+
def self.camelize(snake)
|
11
|
+
snake.to_s.camelize(:lower)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Snake cases a method or argument name.
|
15
|
+
# For example "getStatusCodes" -> 'get_status_codes'.
|
16
|
+
def self.underscore(camel)
|
17
|
+
camel.to_s.underscore
|
18
|
+
end
|
19
|
+
|
20
|
+
end # Util
|
21
|
+
|
22
|
+
end # SslLabs
|
data/lib/ssl_labs.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
require 'ssl_labs/api'
|
5
|
+
require 'ssl_labs/endpoint_data'
|
6
|
+
require 'ssl_labs/host'
|
7
|
+
require 'ssl_labs/info'
|
8
|
+
|
9
|
+
class SslLabs
|
10
|
+
|
11
|
+
# Gem version.
|
12
|
+
VERSION = '0.0.1'
|
13
|
+
|
14
|
+
# User agent for client.
|
15
|
+
USER_AGENT = "ssl_labs.rb #{VERSION}"
|
16
|
+
|
17
|
+
# Seconds to delay between analysis polls.
|
18
|
+
POLL_SLEEP = 10
|
19
|
+
|
20
|
+
attr_accessor :uri
|
21
|
+
attr_accessor :agent
|
22
|
+
|
23
|
+
def initialize(uri=nil)
|
24
|
+
@uri = URI(uri) unless uri.nil?
|
25
|
+
@agent = Mechanize.new
|
26
|
+
@agent.user_agent = USER_AGENT
|
27
|
+
end
|
28
|
+
|
29
|
+
# Run the analyze method and return immediately with Host response
|
30
|
+
# from the server. Do not wait for analysis to complete.
|
31
|
+
def analyze(opts={})
|
32
|
+
defaults = {:host => uri.host}
|
33
|
+
opts_a = opts.flat_map do |k, v|
|
34
|
+
case k
|
35
|
+
when :publish, :clear_cache, :from_cache
|
36
|
+
[k, v ? 'on' : 'off']
|
37
|
+
when :all
|
38
|
+
if v == true
|
39
|
+
[k, 'on']
|
40
|
+
elsif v == :done
|
41
|
+
[k, v]
|
42
|
+
else
|
43
|
+
raise ArgumentError, "Invalid value for option #{k.inspect}"
|
44
|
+
end
|
45
|
+
else
|
46
|
+
raise ArgumentError, "Invalid option #{k.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
json = invoke(:analyze, defaults.merge(Hash[*opts_a]))
|
50
|
+
Host.from_json(json)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Clears the cache and blocks until analyze returns results.
|
54
|
+
# Returns an Array of SslLabs::EndpointData.
|
55
|
+
def analyze!
|
56
|
+
host = analyze(:clear_cache => true)
|
57
|
+
loop do
|
58
|
+
sleep(POLL_SLEEP)
|
59
|
+
host = analyze
|
60
|
+
break if %w{READY ERROR}.include?(host.status)
|
61
|
+
end
|
62
|
+
host.endpoints.map { |ep| endpoint_data(ep) }
|
63
|
+
end
|
64
|
+
|
65
|
+
# Return EndpointData from an EndPoint.
|
66
|
+
def endpoint_data(ep, from_cache=false)
|
67
|
+
body = invoke(:get_endpoint_data,
|
68
|
+
:host => uri.host,
|
69
|
+
:s => ep.ip_address,
|
70
|
+
:from_cache => from_cache ? 'on' : 'off')
|
71
|
+
EndpointData.from_json(body)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return an Info object.
|
75
|
+
def info
|
76
|
+
body = invoke(:info)
|
77
|
+
Info.from_json(body)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Return a Hash of status codes (String => String).
|
81
|
+
def status_codes
|
82
|
+
body = invoke(:get_status_codes)
|
83
|
+
json = JSON.parse(body)
|
84
|
+
json['statusDetails']
|
85
|
+
end
|
86
|
+
|
87
|
+
# Return the Mechanize::Page body for the given method and arguments.
|
88
|
+
def invoke(method, args={})
|
89
|
+
url = Api.url(method, args)
|
90
|
+
@agent.get(url).body
|
91
|
+
end
|
92
|
+
|
93
|
+
end # SslLabs
|
@@ -0,0 +1,153 @@
|
|
1
|
+
{"ipAddress":"69.58.181.89","serverName":"www-ilg.verisign.net",
|
2
|
+
"statusMessage":"Ready","grade":"B","hasWarnings":true,"isExceptional":
|
3
|
+
false,"progress":100,"duration":44127,"eta":1,"delegation":3,"details":{
|
4
|
+
"hostStartTime":1414709783093,"key":{"size":2048,"alg":"RSA",
|
5
|
+
"debianFlaw":false,"strength":2048},"cert":{"subject":
|
6
|
+
"CN\u003dwww.verisign.com,OU\u003dInfrastructure Operations ,O\u003dSymantec Corporation,STREET\u003d350 Ellis Street,L\u003dMountain View,ST\u003dCalifornia,2.5.4.17\u003d#14053934303433,C\u003dUS,2.5.4.5\u003d#130732313538313133,2.5.4.15\u003d#131450726976617465204f7267616e697a6174696f6e,1.3.6.1.4.1.311.60.2.1.2\u003d#130844656c6177617265,1.3.6.1.4.1.311.60.2.1.3\u003d#13025553",
|
7
|
+
"commonNames":["www.verisign.com"],"altNames":["www.verisign.com",
|
8
|
+
"verisign.com","www.verisign.net","verisign.net",
|
9
|
+
"www.verisign.mobi","verisign.mobi","www.verisign.eu",
|
10
|
+
"verisign.eu","forms.ws.symantec.com","sslreview.com",
|
11
|
+
"www.sslreview.com","www.symauth.com"],"notBefore":1389830400000,
|
12
|
+
"notAfter":1452988799000,"issuerSubject":
|
13
|
+
"CN\u003dVeriSign Class 3 Extended Validation SSL SGC CA,OU\u003dTerms of use at https://www.verisign.com/rpa (c)06,OU\u003dVeriSign Trust Network,O\u003dVeriSign, Inc.,C\u003dUS",
|
14
|
+
"sigAlg":"SHA1withRSA","issuerLabel":
|
15
|
+
"VeriSign Class 3 Extended Validation SSL SGC CA","revocationInfo":3,
|
16
|
+
"crlURIs":["http://EVIntl-crl.verisign.com/EVIntl2006.crl"],"ocspURIs":
|
17
|
+
["http://EVIntl-ocsp.verisign.com"],"revocationStatus":2,"scg":1,
|
18
|
+
"validationType":"E","issues":0},"chain":{"certs":[{"subject":
|
19
|
+
"CN\u003dwww.verisign.com,OU\u003dInfrastructure Operations ,O\u003dSymantec Corporation,STREET\u003d350 Ellis Street,L\u003dMountain View,ST\u003dCalifornia,2.5.4.17\u003d#14053934303433,C\u003dUS,2.5.4.5\u003d#130732313538313133,2.5.4.15\u003d#131450726976617465204f7267616e697a6174696f6e,1.3.6.1.4.1.311.60.2.1.2\u003d#130844656c6177617265,1.3.6.1.4.1.311.60.2.1.3\u003d#13025553",
|
20
|
+
"label":"www.verisign.com","issuerSubject":
|
21
|
+
"CN\u003dVeriSign Class 3 Extended Validation SSL SGC CA,OU\u003dTerms of use at https://www.verisign.com/rpa (c)06,OU\u003dVeriSign Trust Network,O\u003dVeriSign, Inc.,C\u003dUS",
|
22
|
+
"issuerLabel":"VeriSign Class 3 Extended Validation SSL SGC CA",
|
23
|
+
"raw":
|
24
|
+
"-----BEGIN CERTIFICATE-----\nMIIG0jCCBbqgAwIBAgIQRHT74McgkNIJ4CcjNXxCZzANBgkqhkiG9w0BAQUFADCBvjELMAkGA1UE\r\nBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO\r\nZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29t\r\nL3JwYSAoYykwNjE4MDYGA1UEAxMvVmVyaVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBWYWxpZGF0aW9u\r\nIFNTTCBTR0MgQ0EwHhcNMTQwMTE2MDAwMDAwWhcNMTYwMTE2MjM1OTU5WjCCASYxEzARBgsrBgEE\r\nAYI3PAIBAxMCVVMxGTAXBgsrBgEEAYI3PAIBAhMIRGVsYXdhcmUxHTAbBgNVBA8TFFByaXZhdGUg\r\nT3JnYW5pemF0aW9uMRAwDgYDVQQFEwcyMTU4MTEzMQswCQYDVQQGEwJVUzEOMAwGA1UEERQFOTQw\r\nNDMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcUDU1vdW50YWluIFZpZXcxGTAXBgNVBAkU\r\nEDM1MCBFbGxpcyBTdHJlZXQxHTAbBgNVBAoUFFN5bWFudGVjIENvcnBvcmF0aW9uMSQwIgYDVQQL\r\nFBtJbmZyYXN0cnVjdHVyZSBPcGVyYXRpb25zICAxGTAXBgNVBAMUEHd3dy52ZXJpc2lnbi5jb20w\r\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrG90iUEhTlnwtoAfqXUHUPBQo3JEKBWEe\r\nwf8/71RFR0O6J5mxF88ODxs/HRGK1wrd8WClqnhMBsvITNB9m+escDpBWpwGNZp4TaYW9HxxtZ7h\r\neaeJjso8M/k3NHdXuFsuPw5L8xxOv9aI0H87LMmImenLxCRmpJQNAKe+jfNTqpuK1tUEYdLzR0n4\r\nu76ZDcGSYSplbCjLcamLTHAhijQQWiUgWC0fUnm4z2zyzT4QwzXIfuf7BCSLfCGY3/KuKO4vybti\r\nUg6ALqMW3JjA149r6DHjIkibwq2wJhFnspm74y0wJq3GE5avUyUrz8XoXexSJPTRuz6jyVayEXeD\r\nZvcJAgMBAAGjggJfMIICWzCB1QYDVR0RBIHNMIHKghB3d3cudmVyaXNpZ24uY29tggx2ZXJpc2ln\r\nbi5jb22CEHd3dy52ZXJpc2lnbi5uZXSCDHZlcmlzaWduLm5ldIIRd3d3LnZlcmlzaWduLm1vYmmC\r\nDXZlcmlzaWduLm1vYmmCD3d3dy52ZXJpc2lnbi5ldYILdmVyaXNpZ24uZXWCFWZvcm1zLndzLnN5\r\nbWFudGVjLmNvbYINc3NscmV2aWV3LmNvbYIRd3d3LnNzbHJldmlldy5jb22CD3d3dy5zeW1hdXRo\r\nLmNvbTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIFoDAoBgNVHSUEITAfBggrBgEFBQcDAQYIKwYB\r\nBQUHAwIGCWCGSAGG+EIEATBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBxcGMCowKAYIKwYBBQUHAgEW\r\nHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9jcHMwHQYDVR0OBBYEFFhbQy8r9duhEyHt180crp3U\r\nFY8gMB8GA1UdIwQYMBaAFE5DyB127zdTek/yWG+U8zji1b3fMD4GA1UdHwQ3MDUwM6AxoC+GLWh0\r\ndHA6Ly9FVkludGwtY3JsLnZlcmlzaWduLmNvbS9FVkludGwyMDA2LmNybDB2BggrBgEFBQcBAQRq\r\nMGgwKwYIKwYBBQUHMAGGH2h0dHA6Ly9FVkludGwtb2NzcC52ZXJpc2lnbi5jb20wOQYIKwYBBQUH\r\nMAKGLWh0dHA6Ly9FVkludGwtYWlhLnZlcmlzaWduLmNvbS9FVkludGwyMDA2LmNlcjANBgkqhkiG\r\n9w0BAQUFAAOCAQEAPSZt7qa0z7AbV78LQ20T2c587Pb389khyLLyxQSx/nKqtYIs0sH9qvsdrqEk\r\n3ThUYbTfI4Owh0a87uCCpBTPf/1c1581waHoId7VibSq3IwR71RPhSJu9zmLJ/GSjs/NWcVgbpUI\r\n7JRQlyqffVmMn3w3La/NZBSXspFSMzmDG0G+hUZJJYPabrfinsedFav2e5BihDgGISbMhxeXGuSs\r\nQYLbOF8B9JPUwgBnDCO6IgKGeww+Zb3Uh1FBmCydpZlP4Qn8tkaegGMXtlv4rzdt7wtKpELSbhot\r\nQHlWr06hD9XUlh7UOBvShhM7UDhMFUQ0HjLf/9A11pb71CRaoHfFbQ\u003d\u003d\r\n-----END CERTIFICATE-----\n"},
|
25
|
+
{"subject":
|
26
|
+
"CN\u003dVeriSign Class 3 Extended Validation SSL SGC CA,OU\u003dTerms of use at https://www.verisign.com/rpa (c)06,OU\u003dVeriSign Trust Network,O\u003dVeriSign, Inc.,C\u003dUS",
|
27
|
+
"label":"VeriSign Class 3 Extended Validation SSL SGC CA",
|
28
|
+
"issuerSubject":
|
29
|
+
"CN\u003dVeriSign Class 3 Public Primary Certification Authority - G5,OU\u003d(c) 2006 VeriSign, Inc. - For authorized use only,OU\u003dVeriSign Trust Network,O\u003dVeriSign, Inc.,C\u003dUS",
|
30
|
+
"issuerLabel":
|
31
|
+
"VeriSign Class 3 Public Primary Certification Authority - G5",
|
32
|
+
"raw":
|
33
|
+
"-----BEGIN CERTIFICATE-----\nMIIGHjCCBQagAwIBAgIQLEjdkw31WY75PJlUemDtQzANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\r\nBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO\r\nZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk\r\nIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp\r\nZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMTYxMTA3MjM1OTU5WjCB\r\nvjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln\r\nbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6Ly93d3cudmVy\r\naXNpZ24uY29tL3JwYSAoYykwNjE4MDYGA1UEAxMvVmVyaVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBW\r\nYWxpZGF0aW9uIFNTTCBTR0MgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9Voi6\r\niDRkZM/NyrDu5xlzxXLZu0W8taj/g74cA9vtibcuEBolvFXKQaGfC88ZXnC5XjlLnjEcX4euKqqo\r\nK6IbOxAjXxOx3QiMThTag4HjtYzjaO0kZ85Wtqybc5ZE24qMs9bwcZOO23FUSutzWWqPcFEsA5+X\r\n0cwRerxiDZUqyRx1V+n1x+q6hDXLx4VafuRN4RGXfQ4gNEXb8aIJ6+s9nriWQ140SwglHkMaotm3\r\nigE0PcP45a9PjP/NZfAjTsWXs1zakByChQ0GDcEitnsopAPDTFPRWLxyvAg5/KB2qKjpS26IPeOz\r\nMSWMcylIDjJ5Bu09Q/T25On8fb6OCNUfAgMBAAGjggIIMIICBDAdBgNVHQ4EFgQUTkPIHXbvN1N6\r\nT/JYb5TzOOLVvd8wEgYDVR0TAQH/BAgwBgEB/wIBADA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggr\r\nBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL2NwczA9BgNVHR8ENjA0MDKgMKAuhixo\r\ndHRwOi8vRVZTZWN1cmUtY3JsLnZlcmlzaWduLmNvbS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMC\r\nAQYwEQYJYIZIAYb4QgEBBAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dp\r\nZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlz\r\naWduLmNvbS92c2xvZ28uZ2lmMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFDbGFzczNDQTIwNDgt\r\nMS00ODAfBgNVHSMEGDAWgBR/02Wnwt3su/AwCfNDOfoCrzMxMzA9BggrBgEFBQcBAQQxMC8wLQYI\r\nKwYBBQUHMAGGIWh0dHA6Ly9FVlNlY3VyZS1vY3NwLnZlcmlzaWduLmNvbTA0BgNVHSUELTArBglg\r\nhkgBhvhCBAEGCmCGSAGG+EUBCAEGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQUFAAOC\r\nAQEAJ3SmNOodneFT1hydDKdbTKln8vAytwEP+0IYON7k7knIE8kL7ATDQHEYcnZDAiNdq3vISBQa\r\nyHsd/PYKnzah0glzcWaWdVE0v5kwUWedVLcmRaxzCCOGJplx9I7X6jmbBgkjv2LdqMS2faSJBz7z\r\nba5AWVB5lzc9Mnh9smNL+eoIaQ4T7ejPu6wFhsoiz4hiXTwiSdhj1SSmve9c48wgOyLq/ETGqOUf\r\n4YbNDE2Pk1PZf+6hCKezMJZJcG6jbD3QY+8lZmPMqrcYF07qcHb2ukKmgDcJTp9miC5rM2bIwHGk\r\nQeta4/wULkuI/a5uW2XpJ+S/5LAjwbJ9W2Il1z4Q1A\u003d\u003d\r\n-----END CERTIFICATE-----\n"},
|
34
|
+
{"subject":
|
35
|
+
"CN\u003dVeriSign Class 3 Public Primary Certification Authority - G5,OU\u003d(c) 2006 VeriSign, Inc. - For authorized use only,OU\u003dVeriSign Trust Network,O\u003dVeriSign, Inc.,C\u003dUS",
|
36
|
+
"label":
|
37
|
+
"VeriSign Class 3 Public Primary Certification Authority - G5",
|
38
|
+
"issuerSubject":
|
39
|
+
"OU\u003dClass 3 Public Primary Certification Authority,O\u003dVeriSign, Inc.,C\u003dUS",
|
40
|
+
"issuerLabel":"Class 3 Public Primary Certification Authority",
|
41
|
+
"raw":
|
42
|
+
"-----BEGIN CERTIFICATE-----\nMIIExjCCBC+gAwIBAgIQNZcxh/OHOgcyfs5YDJt+2jANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQG\r\nEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVibGljIFBy\r\naW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYxMTA4MDAwMDAwWhcNMjExMTA3MjM1\r\nOTU5WjCByjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\r\nZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAt\r\nIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1Ymxp\r\nYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUA\r\nA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i\r\n6CqqpkKzj/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/Wh\r\nkcIzSdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA\r\n5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxp\r\ng8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjggGRMIIBjTAP\r\nBgNVHRMBAf8EBTADAQH/MDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNpZ24uY29t\r\nL3BjYTMuY3JsMA4GA1UdDwEB/wQEAwIBBjA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcC\r\nARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL2NwczAdBgNVHQ4EFgQUf9Nlp8Ld7LvwMAnzQzn6\r\nAq8zMTMwNAYDVR0lBC0wKwYJYIZIAYb4QgQBBgpghkgBhvhFAQgBBggrBgEFBQcDAQYIKwYBBQUH\r\nAwIwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XT\r\nGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYw\r\nNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC52ZXJpc2lnbi5jb20wDQYJ\r\nKoZIhvcNAQEFBQADgYEADyWuSO0bM4VMDLXC1/5N1oMoTEFlYAALd0hxgv5/21oOIMzS6ke8ZEJh\r\nRDR0MIGBJopK90RdfjSAqLiD4gnXbSPdie0oCL1jWhFXCMSe2uJoKK/dUDzsgiHYAMJVRFBwQa2D\r\nF3m6CPMr3u00HUSe0gST9MsFFy0JLS1j7/YmC3s\u003d\r\n-----END CERTIFICATE-----\n"}],
|
43
|
+
"issues":4},"protocols":{"list":[{"id":769,"name":"TLS","version":
|
44
|
+
"1.0"}]},"suites":{"list":[{"id":9,"name":
|
45
|
+
"TLS_RSA_WITH_DES_CBC_SHA","cipherStrength":56,"q":0},{"id":21,
|
46
|
+
"name":"TLS_DHE_RSA_WITH_DES_CBC_SHA","cipherStrength":56,
|
47
|
+
"dhStrength":1024,"dhP":128,"dhG":1,"dhYs":128,"q":0},{"id":4,
|
48
|
+
"name":"TLS_RSA_WITH_RC4_128_MD5","cipherStrength":128},{"id":5,
|
49
|
+
"name":"TLS_RSA_WITH_RC4_128_SHA","cipherStrength":128},{"id":47,
|
50
|
+
"name":"TLS_RSA_WITH_AES_128_CBC_SHA","cipherStrength":128},{"id":
|
51
|
+
51,"name":"TLS_DHE_RSA_WITH_AES_128_CBC_SHA","cipherStrength":
|
52
|
+
128,"dhStrength":1024,"dhP":128,"dhG":1,"dhYs":128},{"id":65,
|
53
|
+
"name":"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA","cipherStrength":128},{
|
54
|
+
"id":69,"name":"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
|
55
|
+
"cipherStrength":128,"dhStrength":1024,"dhP":128,"dhG":1,"dhYs":
|
56
|
+
128},{"id":150,"name":"TLS_RSA_WITH_SEED_CBC_SHA","cipherStrength":
|
57
|
+
128},{"id":154,"name":"TLS_DHE_RSA_WITH_SEED_CBC_SHA",
|
58
|
+
"cipherStrength":128,"dhStrength":1024,"dhP":128,"dhG":1,"dhYs":
|
59
|
+
128},{"id":10,"name":"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
60
|
+
"cipherStrength":168},{"id":22,"name":
|
61
|
+
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA","cipherStrength":168,
|
62
|
+
"dhStrength":1024,"dhP":128,"dhG":1,"dhYs":128},{"id":53,"name":
|
63
|
+
"TLS_RSA_WITH_AES_256_CBC_SHA","cipherStrength":256},{"id":57,
|
64
|
+
"name":"TLS_DHE_RSA_WITH_AES_256_CBC_SHA","cipherStrength":256,
|
65
|
+
"dhStrength":1024,"dhP":128,"dhG":1,"dhYs":128},{"id":132,"name":
|
66
|
+
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA","cipherStrength":256},{"id":
|
67
|
+
136,"name":"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
|
68
|
+
"cipherStrength":256,"dhStrength":1024,"dhP":128,"dhG":1,"dhYs":
|
69
|
+
128}],"preference":false},"serverSignature":"Apache",
|
70
|
+
"prefixDelegation":true,"nonPrefixDelegation":true,"vulnBeast":true,
|
71
|
+
"renegSupport":2,"sessionResumption":2,"compressionMethods":0,
|
72
|
+
"supportsNpn":false,"sessionTickets":1,"ocspStapling":false,
|
73
|
+
"sniRequired":false,"httpStatusCode":200,"supportsRc4":true,
|
74
|
+
"forwardSecrecy":1,"rc4WithModern":false,"sims":{"results":[{"client":{
|
75
|
+
"id":56,"name":"Android","version":"2.3.7","isReference":false},
|
76
|
+
"errorCode":0,"attempts":1,"protocolId":769,"suiteId":4},{"client":
|
77
|
+
{"id":58,"name":"Android","version":"4.0.4","isReference":false},
|
78
|
+
"errorCode":0,"attempts":1,"protocolId":769,"suiteId":57},{
|
79
|
+
"client":{"id":59,"name":"Android","version":"4.1.1","isReference":
|
80
|
+
false},"errorCode":0,"attempts":1,"protocolId":769,"suiteId":
|
81
|
+
57},{"client":{"id":60,"name":"Android","version":"4.2.2",
|
82
|
+
"isReference":false},"errorCode":0,"attempts":1,"protocolId":
|
83
|
+
769,"suiteId":57},{"client":{"id":61,"name":"Android","version":
|
84
|
+
"4.3","isReference":false},"errorCode":0,"attempts":1,
|
85
|
+
"protocolId":769,"suiteId":57},{"client":{"id":62,"name":
|
86
|
+
"Android","version":"4.4.2","isReference":false},"errorCode":0,
|
87
|
+
"attempts":1,"protocolId":769,"suiteId":57},{"client":{"id":41,
|
88
|
+
"name":"BingBot","version":"Dec 2013","isReference":false},
|
89
|
+
"errorCode":0,"attempts":1,"protocolId":769,"suiteId":47},{
|
90
|
+
"client":{"id":74,"name":"BingPreview","version":"Jun 2014",
|
91
|
+
"isReference":false},"errorCode":0,"attempts":1,"protocolId":
|
92
|
+
769,"suiteId":57},{"client":{"id":80,"name":"Chrome","platform":
|
93
|
+
"OS X","version":"37","isReference":true},"errorCode":0,
|
94
|
+
"attempts":1,"protocolId":769,"suiteId":51},{"client":{"id":48,
|
95
|
+
"name":"Firefox","platform":"Win 7","version":"24.2.0 ESR",
|
96
|
+
"isReference":false},"errorCode":0,"attempts":1,"protocolId":
|
97
|
+
769,"suiteId":136},{"client":{"id":79,"name":"Firefox","platform":
|
98
|
+
"OS X","version":"32","isReference":true},"errorCode":0,
|
99
|
+
"attempts":1,"protocolId":769,"suiteId":51},{"client":{"id":72,
|
100
|
+
"name":"Googlebot","version":"Jun 2014","isReference":false},
|
101
|
+
"errorCode":0,"attempts":1,"protocolId":769,"suiteId":5},{"client":
|
102
|
+
{"id":18,"name":"IE","platform":"XP","version":"6","isReference":
|
103
|
+
false},"errorCode":1,"attempts":1},{"client":{"id":19,"name":
|
104
|
+
"IE","platform":"Vista","version":"7","isReference":false},
|
105
|
+
"errorCode":0,"attempts":1,"protocolId":769,"suiteId":47},{
|
106
|
+
"client":{"id":20,"name":"IE","platform":"XP","version":"8",
|
107
|
+
"isReference":false},"errorCode":0,"attempts":1,"protocolId":
|
108
|
+
769,"suiteId":4},{"client":{"id":23,"name":"IE","platform":
|
109
|
+
"Win 7","version":"8-10","isReference":true},"errorCode":0,
|
110
|
+
"attempts":1,"protocolId":769,"suiteId":47},{"client":{"id":23,
|
111
|
+
"name":"IE","platform":"Win 7","version":"11","isReference":
|
112
|
+
true},"errorCode":0,"attempts":1,"protocolId":769,"suiteId":47},{
|
113
|
+
"client":{"id":71,"name":"IE","platform":"Win 8.1","version":
|
114
|
+
"11","isReference":true},"errorCode":0,"attempts":1,"protocolId":
|
115
|
+
769,"suiteId":53},{"client":{"id":81,"name":"IE","platform":
|
116
|
+
"Win 10 Preview","version":"11","isReference":true},"errorCode":
|
117
|
+
0,"attempts":1,"protocolId":769,"suiteId":53},{"client":{"id":64,
|
118
|
+
"name":"IE Mobile","platform":"Win Phone 8.0","version":"10",
|
119
|
+
"isReference":false},"errorCode":0,"attempts":1,"protocolId":
|
120
|
+
769,"suiteId":47},{"client":{"id":65,"name":"IE Mobile","platform":
|
121
|
+
"Win Phone 8.1","version":"11","isReference":false},"errorCode":
|
122
|
+
0,"attempts":1,"protocolId":769,"suiteId":47},{"client":{"id":25,
|
123
|
+
"name":"Java","version":"6u45","isReference":false},"errorCode":
|
124
|
+
0,"attempts":1,"protocolId":769,"suiteId":4},{"client":{"id":26,
|
125
|
+
"name":"Java","version":"7u25","isReference":false},"errorCode":
|
126
|
+
0,"attempts":1,"protocolId":769,"suiteId":47},{"client":{"id":53,
|
127
|
+
"name":"Java","version":"8b132","isReference":false},"errorCode":
|
128
|
+
0,"attempts":1,"protocolId":769,"suiteId":47},{"client":{"id":27,
|
129
|
+
"name":"OpenSSL","version":"0.9.8y","isReference":false},
|
130
|
+
"errorCode":0,"attempts":1,"protocolId":769,"suiteId":57},{
|
131
|
+
"client":{"id":28,"name":"OpenSSL","version":"1.0.1h",
|
132
|
+
"isReference":false},"errorCode":0,"attempts":1,"protocolId":
|
133
|
+
769,"suiteId":57},{"client":{"id":32,"name":"Safari","platform":
|
134
|
+
"OS X 10.6.8","version":"5.1.9","isReference":false},"errorCode":
|
135
|
+
0,"attempts":1,"protocolId":769,"suiteId":47},{"client":{"id":33,
|
136
|
+
"name":"Safari","platform":"iOS 6.0.1","version":"6",
|
137
|
+
"isReference":true},"errorCode":0,"attempts":1,"protocolId":
|
138
|
+
769,"suiteId":47},{"client":{"id":63,"name":"Safari","platform":
|
139
|
+
"iOS 7.1","version":"7","isReference":true},"errorCode":0,
|
140
|
+
"attempts":1,"protocolId":769,"suiteId":47},{"client":{"id":75,
|
141
|
+
"name":"Safari","platform":"iOS 8.0 Beta","version":"8",
|
142
|
+
"isReference":true},"errorCode":0,"attempts":1,"protocolId":
|
143
|
+
769,"suiteId":57},{"client":{"id":34,"name":"Safari","platform":
|
144
|
+
"OS X 10.8.4","version":"6.0.4","isReference":true},"errorCode":
|
145
|
+
0,"attempts":1,"protocolId":769,"suiteId":47},{"client":{"id":35,
|
146
|
+
"name":"Safari","platform":"OS X 10.9","version":"7",
|
147
|
+
"isReference":true},"errorCode":0,"attempts":1,"protocolId":
|
148
|
+
769,"suiteId":47},{"client":{"id":73,"name":"Yahoo Slurp",
|
149
|
+
"version":"Jun 2014","isReference":false},"errorCode":0,
|
150
|
+
"attempts":1,"protocolId":769,"suiteId":57},{"client":{"id":78,
|
151
|
+
"name":"YandexBot","version":"Sep 2014","isReference":false},
|
152
|
+
"errorCode":0,"attempts":1,"protocolId":769,"suiteId":57}]},
|
153
|
+
"heartbleed":false,"heartbeat":false,"openSslCcs":2}}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'json'
|
2
|
+
#require 'pry'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
require 'ssl_labs'
|
6
|
+
|
7
|
+
class TestEndpointData < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def test_constructor
|
10
|
+
json = File.read(File.join(File.dirname(__FILE__), 'endpoint_data.json'))
|
11
|
+
hash = JSON.parse(json)
|
12
|
+
epd = SslLabs::EndpointData.from_hash(hash)
|
13
|
+
# XXX insert tests here
|
14
|
+
#binding.pry
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ssl_labs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Martin Carpenter
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mechanize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.8.1
|
41
|
+
description: A gem to interface with ssllabs.com scanner
|
42
|
+
email: mcarpenter@free.fr
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files:
|
46
|
+
- Rakefile
|
47
|
+
- README.md
|
48
|
+
files:
|
49
|
+
- lib/ssl_labs.rb
|
50
|
+
- lib/ssl_labs/api.rb
|
51
|
+
- lib/ssl_labs/endpoint.rb
|
52
|
+
- lib/ssl_labs/endpoint_data.rb
|
53
|
+
- lib/ssl_labs/endpoint_data/details.rb
|
54
|
+
- lib/ssl_labs/endpoint_data/details/cert.rb
|
55
|
+
- lib/ssl_labs/endpoint_data/details/chain.rb
|
56
|
+
- lib/ssl_labs/endpoint_data/details/key.rb
|
57
|
+
- lib/ssl_labs/endpoint_data/details/protocol.rb
|
58
|
+
- lib/ssl_labs/endpoint_data/details/sim.rb
|
59
|
+
- lib/ssl_labs/endpoint_data/details/sim/client.rb
|
60
|
+
- lib/ssl_labs/endpoint_data/details/suite.rb
|
61
|
+
- lib/ssl_labs/host.rb
|
62
|
+
- lib/ssl_labs/info.rb
|
63
|
+
- lib/ssl_labs/util.rb
|
64
|
+
- test/endpoint_data.json
|
65
|
+
- test/test_endpoint_data.rb
|
66
|
+
- Rakefile
|
67
|
+
- README.md
|
68
|
+
homepage: https://github.com/mcarpenter/ssl_labs.rb
|
69
|
+
licenses:
|
70
|
+
- Apache 2.0
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.0.3
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: ssllabs.com SSL/TLS vulnerability scanning client
|
92
|
+
test_files:
|
93
|
+
- test/test_endpoint_data.rb
|