ssl-test 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 11a0ae9638ae444932d7eef5c49873e276056235
4
- data.tar.gz: 3c9bec83c428f62c6f0e84559b4daf5687d4682e
2
+ SHA256:
3
+ metadata.gz: 3f6f73059bf9880985e8564282104fa677ecf3016872948d4047d47589f4ff12
4
+ data.tar.gz: 2c5580091f64589290c5bda90b25172c5d78dab67c9a1a40829e3e2cc35bc98f
5
5
  SHA512:
6
- metadata.gz: ea7b409ae5b9a83bf1ddfb3cfc844a4d8dd55d2aabbbf943c1f924e868b31ddb8b5aef0ecb6b2875652da476b50149939076f574ca3400ca9251901c2eb6ab56
7
- data.tar.gz: dac29c015557a0ecc1470487d441962f2d4fbb6b8b1e458c931bf12b6ff2c2c42fc87070414a6b365febb7d0757808b712243c21f2f652fcc1a1042cfe3c0735
6
+ metadata.gz: 280ea4637845f7df589dfbc07ea51459a5fefaa36b36bb17614beb6fb809bc71f5d36a70e3ccc7e8fba61383b5ad0ba24e9fd49f066636792968ac6f132e5793
7
+ data.tar.gz: dc96640201b5098695be42467d052f592a2d3bf59d38e9cfbe1028bf7984226d46ec058ad35381383886cb84e7e348af07bf8429c67eed7d4fcafc8c89c3fe8f
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.4.3
5
+ - 2.5.0
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # SSLTest
1
+ # SSLTest [![Build Status](https://travis-ci.org/jarthod/ssl-test.svg?branch=master)](https://travis-ci.org/jarthod/ssl-test) [![Depfu](https://badges.depfu.com/badges/0d732c9cbec3fdaaac7c5ba5583269db/overview.svg)](https://depfu.com/github/jarthod/ssl-test)
2
2
 
3
3
  A small ruby gem to help you test a website's SSL certificate.
4
4
 
@@ -58,12 +58,14 @@ Pretty much the same errors `curl` will:
58
58
  - Incomplete certificate chain (missing intermediary)
59
59
  - Self signed certificates
60
60
  - Valid certs used with incorect hostname
61
+ - Untrusted root (if your system is up-to-date)
62
+ - And more...
61
63
 
62
64
  ### GOTCHA: errors SSLTest will NOT detect
63
65
 
64
66
  There is a spefic kind or error this code will **NOT** detect: *revoked certificates*. This is much more complex to handle because it needs an up to date database of revoked certs to check with. This is implemented in most modern browsers but the results vary greatly (chrome ignores this for example).
65
67
 
66
- Here is an example of website with a revoked certificate: https://revoked.grc.com/
68
+ Here is an example of website with a revoked certificate: https://revoked.badssl.com/
67
69
 
68
70
  Any contribution to add this feature is greatly appreciated :)
69
71
 
@@ -1,7 +1,7 @@
1
1
  require "net/https"
2
2
 
3
3
  module SSLTest
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
 
6
6
  def self.test url, open_timeout: 5, read_timeout: 5
7
7
  uri = URI.parse(url)
@@ -15,19 +15,45 @@ module SSLTest
15
15
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
16
16
  http.verify_callback = -> (verify_ok, store_context) {
17
17
  cert = store_context.current_cert
18
- failed_cert_reason = [store_context.error, store_context.error_string] if !verify_ok
18
+ failed_cert_reason = [store_context.error, store_context.error_string] if store_context.error != 0
19
19
  verify_ok
20
20
  }
21
21
 
22
22
  begin
23
- res = http.start { }
23
+ http.start { }
24
24
  return [true, nil, cert]
25
25
  rescue OpenSSL::SSL::SSLError => e
26
26
  error = e.message
27
27
  error = "error code %d: %s" % failed_cert_reason if failed_cert_reason
28
+ if error =~ /certificate verify failed/
29
+ domains = cert_domains(cert)
30
+ if matching_domains(domains, uri.host).none?
31
+ error = "hostname \"#{uri.host}\" does not match the server certificate (#{domains.join(', ')})"
32
+ end
33
+ end
28
34
  return [false, error, cert]
29
35
  rescue => e
30
36
  return [nil, "SSL certificate test failed: #{e.message}"]
31
37
  end
32
38
  end
39
+
40
+ def self.cert_field_to_hash field
41
+ field.to_a.each.with_object({}) do |v, h|
42
+ v = v.to_a
43
+ h[v[0]] = v[1].encode('UTF-8', undef: :replace, invalid: :replace)
44
+ end
45
+ end
46
+
47
+ def self.cert_domains cert
48
+ (Array(cert_field_to_hash(cert.subject)['CN']) +
49
+ cert_field_to_hash(cert.extensions)['subjectAltName'].split(/\s*,\s*/))
50
+ .compact
51
+ .map {|s| s.gsub(/^DNS:/, '') }
52
+ .uniq
53
+ end
54
+
55
+ def self.matching_domains domains, hostname
56
+ domains.map {|s| Regexp.new("\A#{Regexp.escape(s).gsub('\*', '[^.]+')}\z") }
57
+ .select {|domain| domain.match?(hostname) }
58
+ end
33
59
  end
@@ -18,5 +18,6 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  spec.add_development_dependency "bundler", "~> 1.7"
21
- spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "minitest"
22
23
  end
@@ -11,6 +11,20 @@ describe SSLTest do
11
11
  cert.must_be_instance_of OpenSSL::X509::Certificate
12
12
  end
13
13
 
14
+ it "returns no error on valid SAN" do
15
+ valid, error, cert = SSLTest.test("https://1000-sans.badssl.com/")
16
+ error.must_be_nil
17
+ valid.must_equal true
18
+ cert.must_be_instance_of OpenSSL::X509::Certificate
19
+ end
20
+
21
+ it "returns no error when no CN" do
22
+ valid, error, cert = SSLTest.test("https://no-common-name.badssl.com/")
23
+ error.must_be_nil
24
+ valid.must_equal true
25
+ cert.must_be_instance_of OpenSSL::X509::Certificate
26
+ end
27
+
14
28
  it "works with websites blocking http requests" do
15
29
  valid, error, cert = SSLTest.test("https://obyava.ua")
16
30
  error.must_be_nil
@@ -19,21 +33,28 @@ describe SSLTest do
19
33
  end
20
34
 
21
35
  it "returns error on self signed certificate" do
22
- valid, error, cert = SSLTest.test("https://kernelcoffee.org")
36
+ valid, error, cert = SSLTest.test("https://self-signed.badssl.com/")
23
37
  error.must_equal "error code 18: self signed certificate"
24
38
  valid.must_equal false
25
39
  cert.must_be_instance_of OpenSSL::X509::Certificate
26
40
  end
27
41
 
42
+ it "returns error on untrusted root" do
43
+ valid, error, cert = SSLTest.test("https://untrusted-root.badssl.com/")
44
+ error.must_equal "error code 20: unable to get local issuer certificate"
45
+ valid.must_equal false
46
+ cert.must_be_instance_of OpenSSL::X509::Certificate
47
+ end
48
+
28
49
  it "returns error on invalid host" do
29
- valid, error, cert = SSLTest.test("https://web1.updn.io")
30
- error.must_equal 'hostname "web1.updn.io" does not match the server certificate'
50
+ valid, error, cert = SSLTest.test("https://wrong.host.badssl.com/")
51
+ error.must_equal 'hostname "wrong.host.badssl.com" does not match the server certificate (*.badssl.com, badssl.com)'
31
52
  valid.must_equal false
32
53
  cert.must_be_instance_of OpenSSL::X509::Certificate
33
54
  end
34
55
 
35
56
  it "returns error on expired cert" do
36
- valid, error, cert = SSLTest.test("https://testssl-expire.disig.sk")
57
+ valid, error, cert = SSLTest.test("https://expired.badssl.com/")
37
58
  error.must_equal "error code 10: certificate has expired"
38
59
  valid.must_equal false
39
60
  cert.must_be_instance_of OpenSSL::X509::Certificate
@@ -55,9 +76,9 @@ describe SSLTest do
55
76
 
56
77
  # Not implemented yet
57
78
  # it "returns error on revoked cert" do
58
- # valid, error, cert = SSLTest.test("https://revoked.grc.com")
59
- # valid.must_equal false
79
+ # valid, error, cert = SSLTest.test("https://revoked.badssl.com/")
60
80
  # error.must_equal "error code XX: certificate has been revoked"
81
+ # valid.must_equal false
61
82
  # cert.must_be_instance_of OpenSSL::X509::Certificate
62
83
  # end
63
84
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ssl-test
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrien Jarthon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-13 00:00:00.000000000 Z
11
+ date: 2018-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,16 +28,30 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
- version: '10.0'
54
+ version: '0'
41
55
  description:
42
56
  email:
43
57
  - jobs@adrienjarthon.com
@@ -46,6 +60,7 @@ extensions: []
46
60
  extra_rdoc_files: []
47
61
  files:
48
62
  - ".gitignore"
63
+ - ".travis.yml"
49
64
  - Gemfile
50
65
  - LICENSE.txt
51
66
  - README.md
@@ -73,10 +88,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
88
  version: '0'
74
89
  requirements: []
75
90
  rubyforge_project:
76
- rubygems_version: 2.5.1
91
+ rubygems_version: 2.7.3
77
92
  signing_key:
78
93
  specification_version: 4
79
94
  summary: Test website SSL certificate validity
80
95
  test_files:
81
96
  - test/ssl-test_test.rb
82
- has_rdoc: