tls-checker 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab14c3e081bec34c6623b35ee52b0e26e544242b21ff50a484c9780d73940585
4
- data.tar.gz: 1de5b2c8fae2bb03564a23d751ac04240ea64003a7022cf7d5779d6f61b478e5
3
+ metadata.gz: 1cdde3a84021818453f8783a575370df091b421bc8ec46b9f37eea6afea7c68d
4
+ data.tar.gz: f197dbf9cf67fccb5e6f5d757929ea6f145d5fbff77f0ed6adb311b362154e11
5
5
  SHA512:
6
- metadata.gz: f14c9c95cb25b5e36f5b8a1e1799cc18900e31f66790456704a4c866a65c47f165247a64d5795f9e22de3d87a6d89701d8726a3c4639f5fe5bc0d9bf4ccb07d3
7
- data.tar.gz: 413fc601fb7b4d410f6dc8f6518d982056b06f4144625e2d900a1f3c0b300d8b58c8ed039d533d13872b21d8cc7cd92ec73b13e35c651e374203d953c111dddc
6
+ metadata.gz: 59c569e106f22433b88cfd2480a8aad515b6cecedc1e50eaa533b907bb09711e7e90f58f4ed8ec7ecdb6781e17910eee527a72f903a187bb0f125ec1788314be
7
+ data.tar.gz: 4771ef041e39cb1da7aaae82f5508fc528dd3980a3f4fab0fa8907e89395f0c788e951d15fb8c0bb9d38b2108760b635661a9dfb4c393da2ea233614089f71be
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  language: ruby
3
3
  rvm:
4
+ - 2.3
4
5
  - 2.4
5
6
  - 2.5
6
7
  - 2.6
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.1.0]
9
+
10
+ ### Added
11
+
12
+ - Make it possible to test services using an IP address;
13
+ - Report validity of certificates when a TLSA record is found in the DNS.
14
+
15
+ [Unreleased]: https://github.com/smortex/tls-checker/compare/v1.1.0...HEAD
16
+ [1.1.0]: https://github.com/smortex/tls-checker/compare/v1.0.0...v1.1.0
@@ -3,3 +3,5 @@
3
3
  require 'tls-checker/certificate_checker'
4
4
  require 'tls-checker/certificate_checker_factory'
5
5
  require 'tls-checker/line_oriented_socket'
6
+ require 'tls-checker/tlsa_checker'
7
+ require 'tls-checker/tlsa_checker_factory'
@@ -6,8 +6,6 @@ require 'internet_security_event'
6
6
 
7
7
  module TLSChecker
8
8
  class CertificateChecker
9
- include ActionView::Helpers::DateHelper
10
-
11
9
  def initialize(hostname, address, port, starttls)
12
10
  @hostname = hostname
13
11
  @address = address
@@ -31,7 +29,7 @@ module TLSChecker
31
29
  }
32
30
  end.merge(
33
31
  service: service,
34
- ttl: 3600 * 12,
32
+ ttl: 12.hours,
35
33
  tags: ['tls-checker'],
36
34
  )
37
35
  end
@@ -40,10 +38,16 @@ module TLSChecker
40
38
  description
41
39
  end
42
40
 
43
- private
41
+ def certificate
42
+ @certificate = OpenSSL::X509::Certificate.new(tls_socket.peer_cert) if @certificate.nil?
43
+ @certificate
44
+ rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, SocketRecvTimeout => e
45
+ @certificate_failure = e.message
46
+ @certificate = false
47
+ end
44
48
 
45
49
  def service
46
- format('X.509/%<hostname>s/%<address>s:%<port>d', hostname: hostname, address: humanized_address, port: port)
50
+ "X.509/#{hostname}/#{humanized_address}:#{port}"
47
51
  end
48
52
 
49
53
  def humanized_address
@@ -54,13 +58,7 @@ module TLSChecker
54
58
  end
55
59
  end
56
60
 
57
- def certificate
58
- @certificate = OpenSSL::X509::Certificate.new(tls_socket.peer_cert) if @certificate.nil?
59
- @certificate
60
- rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, SocketRecvTimeout => e
61
- @certificate_failure = e.message
62
- @certificate = false
63
- end
61
+ private
64
62
 
65
63
  def tls_socket
66
64
  @tls_socket ||= case starttls
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ipaddr'
4
+
3
5
  module TLSChecker
4
6
  class CertificateCheckerFactory
5
7
  def initialize
@@ -14,7 +16,25 @@ module TLSChecker
14
16
 
15
17
  port ||= port_for(hostname)
16
18
  starttls ||= starttls_for(port)
17
- @resolver.getaddresses(hostname).map { |ip| CertificateChecker.new(hostname, ip, port, starttls) }
19
+
20
+ begin
21
+ ip_in_hostname = IPAddr.new(hostname)
22
+
23
+ [
24
+ CertificateChecker.new(nil, ip_in_hostname, port, starttls),
25
+ ]
26
+ rescue IPAddr::InvalidAddressError
27
+ certificate_checkers = @resolver.getaddresses(hostname).map { |ip| CertificateChecker.new(hostname, ip, port, starttls) }
28
+
29
+ factory = TLSACheckerFactory.new
30
+
31
+ tlsa_checkers = []
32
+ certificate_checkers.each do |certificate_checker|
33
+ tlsa_checkers += factory.tlsa_checkers_for(certificate_checker)
34
+ end
35
+
36
+ certificate_checkers + tlsa_checkers
37
+ end
18
38
  end
19
39
 
20
40
  private
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TLSChecker
4
+ class TLSAChecker < InternetSecurityEvent::TLSAStatus
5
+ def initialize(record, certificate_checker)
6
+ super(record, certificate_checker.certificate)
7
+
8
+ @certificate_checker = certificate_checker
9
+ end
10
+
11
+ def to_e
12
+ super.merge(
13
+ service: service,
14
+ ttl: 12.hours,
15
+ )
16
+ end
17
+
18
+ private
19
+
20
+ def service
21
+ "#{@certificate_checker.service}/TLSA"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TLSChecker
4
+ class TLSACheckerFactory
5
+ def initialize
6
+ @resolver = Resolv::DNS.new
7
+ end
8
+
9
+ def tlsa_checkers_for(certificate_checker)
10
+ res = []
11
+
12
+ each_tlsa_end_entity_record(certificate_checker) do |record|
13
+ checker = TLSAChecker.new(record, certificate_checker)
14
+ # Since a single domain may have different certificates on different
15
+ # addresses, we are not interested in reporting failures here: a server
16
+ # with 3 certificates on 3 IP addresses is expected to have 3 TLSA
17
+ # records in the DNS, each one being valid for a different certificate.
18
+ #
19
+ # By adding only valid certificates, we can still detect problems when
20
+ # events expire.
21
+ next unless checker.certificate_match_tlsa_record?
22
+
23
+ res << checker
24
+ end
25
+
26
+ res
27
+ end
28
+
29
+ private
30
+
31
+ def each_tlsa_end_entity_record(certificate_checker)
32
+ each_tlsa_record(certificate_checker) do |record|
33
+ next unless record.end_entity?
34
+
35
+ yield(record)
36
+ end
37
+ end
38
+
39
+ def each_tlsa_record(certificate_checker)
40
+ resource = "_#{certificate_checker.port}._tcp.#{certificate_checker.hostname}."
41
+
42
+ @resolver.getresources(resource, Resolv::DNS::Resource::IN::ANY).each do |rr|
43
+ # XXX: Should we check the RRSIG here, or can we assume that the resolver
44
+ # should have failed if it could not verify the response?
45
+ next unless rr.class.name == 'Resolv::DNS::Resource::Generic::Type52_Class1'
46
+
47
+ record = Resolv::DNS::Resource::IN::TLSA.new(rr.data)
48
+ yield(record)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TlsChecker
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ['lib']
25
25
 
26
- spec.add_dependency 'internet_security_event', '~> 1.0'
26
+ spec.add_dependency 'internet_security_event', '~> 1.1'
27
27
 
28
28
  spec.add_development_dependency 'bundler'
29
29
  spec.add_development_dependency 'midi-smtp-server'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tls-checker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Romain Tartière
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-02-19 00:00:00.000000000 Z
11
+ date: 2019-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: internet_security_event
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '1.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '1.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -105,6 +105,7 @@ files:
105
105
  - ".gitignore"
106
106
  - ".rspec"
107
107
  - ".travis.yml"
108
+ - CHANGELOG.md
108
109
  - CODE_OF_CONDUCT.md
109
110
  - Gemfile
110
111
  - LICENSE.txt
@@ -117,6 +118,8 @@ files:
117
118
  - lib/tls-checker/certificate_checker.rb
118
119
  - lib/tls-checker/certificate_checker_factory.rb
119
120
  - lib/tls-checker/line_oriented_socket.rb
121
+ - lib/tls-checker/tlsa_checker.rb
122
+ - lib/tls-checker/tlsa_checker_factory.rb
120
123
  - lib/tls-checker/version.rb
121
124
  - tls-checker.gemspec
122
125
  homepage: https://github.com/smortex/tls-checker
@@ -138,8 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
141
  - !ruby/object:Gem::Version
139
142
  version: '0'
140
143
  requirements: []
141
- rubyforge_project:
142
- rubygems_version: 2.7.8
144
+ rubygems_version: 3.0.2
143
145
  signing_key:
144
146
  specification_version: 4
145
147
  summary: Report expired/about to expires certificates used in TLS connexions