internet_security_event 1.0.2 → 1.2.1

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
2
  SHA256:
3
- metadata.gz: c45d13b633f75d73835bc5df4366f4c7dc778637124b04dfcca841d170062bb8
4
- data.tar.gz: 51012612ff7d23ae2019471663f7c16b50d04665f467efad9a13abd377662cbc
3
+ metadata.gz: 3df07baf6dbb78e612229fee0043e79a955c01f7f1655c8e77a6a142340d4114
4
+ data.tar.gz: 53bd006f3735a68a8d8255e5c83245f636eb69bd9957c581fa65a6d094c0e0ea
5
5
  SHA512:
6
- metadata.gz: ba96b78855a50ce723f9f26c869d9b65a4f0261d79730139c16bac20c56ffd9bfd01921f3152cd94c10648d7ae262474cadda190f5c433e48913a00f9a6b62ab
7
- data.tar.gz: c77cf433031d25d2c61089e098db1a097853432449060bd1600e66ef5d2a6c37a0a3065182ffb2dcb623222da708898dfe6ffb5b5ccc5a59301adbc1308a7446
6
+ metadata.gz: 2f3cdfec986f3112a037f78eb7579f6adca58b09361cfeea297a0c1d941409871312524cd14cf1bfa2534c50b255f7ebb4ec2e0d82085413d6096d5783f444ec
7
+ data.tar.gz: e49b5770d869368c49786ad8997cf85f4178f7cf52fef2eac957018db45c0ebeb0210d0bd225fc1339dc4bb215acacf52d37b55c9b0d5f205049d98b70de6621
@@ -0,0 +1,50 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+
11
+ jobs:
12
+ rubocop:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - name: Setup ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: 3.0
20
+ bundler-cache: true
21
+ - name: Run static code analysis
22
+ run: bundle exec rubocop
23
+ unit:
24
+ runs-on: ubuntu-latest
25
+ needs: rubocop
26
+ strategy:
27
+ matrix:
28
+ ruby:
29
+ - "2.6"
30
+ - "2.7"
31
+ - "3.0"
32
+ - "3.1"
33
+ name: Ruby ${{ matrix.ruby }}
34
+ steps:
35
+ - uses: actions/checkout@v2
36
+ - name: Setup ruby
37
+ uses: ruby/setup-ruby@v1
38
+ with:
39
+ ruby-version: ${{ matrix.ruby }}
40
+ bundler-cache: true
41
+ - name: Run tests without uploading code coverage
42
+ if: ${{ matrix.ruby != '3.0' }}
43
+ run: bundle exec rake
44
+ - name: Run tests and upload coverage to Code Climate
45
+ if: ${{ matrix.ruby == '3.0' }}
46
+ uses: paambaati/codeclimate-action@v3.0.0
47
+ env:
48
+ CC_TEST_REPORTER_ID: ${{ secrets.CODECLIMATE_TOKEN }}
49
+ with:
50
+ coverageCommand: bundle exec rake
data/.rspec CHANGED
@@ -1,3 +1 @@
1
- --format documentation
2
- --color
3
1
  --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,25 @@
1
+ AllCops:
2
+ AllowSymlinksInCacheRootDirectory: true
3
+
4
+ require:
5
+ - rubocop-rake
6
+ - rubocop-rspec
7
+
8
+ Layout/HashAlignment:
9
+ EnforcedColonStyle: table
10
+ EnforcedHashRocketStyle: table
11
+
12
+ Metrics/LineLength:
13
+ Max: 160
14
+
15
+ Style/Documentation:
16
+ Enabled: false
17
+
18
+ Style/TrailingCommaInArrayLiteral:
19
+ EnforcedStyleForMultiline: comma
20
+
21
+ Style/TrailingCommaInHashLiteral:
22
+ EnforcedStyleForMultiline: comma
23
+
24
+ Style/TrailingCommaInArguments:
25
+ EnforcedStyleForMultiline: comma
data/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
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.2.1] - 2022-07-15
9
+
10
+ ### Changed
11
+ - Emit a `warning` state instead of a `warn` state to match Riemann wording.
12
+
13
+ ## [1.2.0] - 2019-02-28
14
+
15
+ ### Changed
16
+ - Rely on `OpenSSL::SSL.verify_certificate_identity` to check that a certificate
17
+ is valid for the provided hostname.
18
+
19
+ ## [1.1.0] - 2019-02-21
20
+
21
+ ### Added
22
+ - Add basic suport for TLSA events.
23
+
24
+ ## [1.0.2] - 2019-02-21
25
+
26
+ ### Changed
27
+ - Fix checking of TLS hostnames with wildcard certificates.
28
+
29
+ ## [1.0.1] - 2019-02-18
30
+
31
+ ### Changed
32
+ - Improve the way TLS certificates state is computed.
33
+
34
+ [Unreleased]: https://github.com/smortex/internet_security_event/compare/v1.2.0...HEAD
35
+ [1.2.0]: https://github.com/smortex/internet_security_event/compare/v1.1.0...v1.2.0
36
+ [1.1.0]: https://github.com/smortex/internet_security_event/compare/v1.0.2...v1.1.0
37
+ [1.0.2]: https://github.com/smortex/internet_security_event/compare/v1.0.1...v1.0.2
38
+ [1.0.1]: https://github.com/smortex/internet_security_event/compare/v1.0.0...v1.0.1
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # InternetSecurityEvent
2
2
 
3
- [![Build Status](https://travis-ci.com/smortex/internet_security_event.svg?branch=master)](https://travis-ci.com/smortex/internet_security_event)
3
+ [![Build Status](https://github.com/smortex/internet_security_event/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/smortex/internet_security_event/actions/workflows/ci.yml)
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/bc64fb4f1c1088c15b8c/maintainability)](https://codeclimate.com/github/smortex/internet_security_event/maintainability)
5
5
  [![Test Coverage](https://api.codeclimate.com/v1/badges/bc64fb4f1c1088c15b8c/test_coverage)](https://codeclimate.com/github/smortex/internet_security_event/test_coverage)
6
6
 
@@ -38,7 +38,7 @@ certificate = OpenSSL::X509::Certificate.new(...)
38
38
 
39
39
  event = InternetSecurityEvent::X509Status.build(certificate)
40
40
 
41
- event[:state] #=> 'ok', 'warn', 'critical'
41
+ event[:state] #=> 'ok', 'warning', 'critical'
42
42
  event[:description] #=> Human readable state
43
43
  event[:metric] #=> an optional Float
44
44
  ```
@@ -81,4 +81,4 @@ License](https://opensource.org/licenses/MIT).
81
81
 
82
82
  Everyone interacting in the InternetSecurityEvent project’s codebases, issue
83
83
  trackers, chat rooms and mailing lists is expected to follow the [code of
84
- conduct](https://github.com/smortex/internet_security_event/blob/master/CODE_OF_CONDUCT.md).
84
+ conduct](https://github.com/smortex/internet_security_event/blob/main/CODE_OF_CONDUCT.md).
@@ -13,6 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.summary = 'Build events describing the status of various internet services'
14
14
  spec.homepage = 'https://github.com/smortex/internet_security_event'
15
15
  spec.license = 'MIT'
16
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
16
17
 
17
18
  # Specify which files should be added to the gem when it is released.
18
19
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -23,11 +24,13 @@ Gem::Specification.new do |spec|
23
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
25
  spec.require_paths = ['lib']
25
26
 
26
- spec.add_dependency 'actionview', '~> 5.2'
27
27
  spec.add_dependency 'activesupport', '~> 5.2'
28
28
 
29
29
  spec.add_development_dependency 'bundler'
30
30
  spec.add_development_dependency 'rake'
31
31
  spec.add_development_dependency 'rspec'
32
+ spec.add_development_dependency 'rubocop'
33
+ spec.add_development_dependency 'rubocop-rake'
34
+ spec.add_development_dependency 'rubocop-rspec'
32
35
  spec.add_development_dependency 'simplecov'
33
36
  end
@@ -33,36 +33,7 @@ module InternetSecurityEvent
33
33
  def hostname_is_valid_for_this_certificate?
34
34
  return true if hostname.nil?
35
35
 
36
- hostname_match_subject? || hostname_match_subject_alternative_name?
37
- end
38
-
39
- def hostname_match_subject?
40
- name_match_patern(hostname, common_name)
41
- end
42
-
43
- def hostname_match_subject_alternative_name?
44
- return false unless certificate
45
-
46
- san = certificate.extensions.select { |ext| ext.oid == 'subjectAltName' }.first
47
-
48
- if san
49
- alt_names = san.value.split(', ').map { |name| name.sub(/\ADNS:/, '') }
50
- return true if alt_names.any? { |alt_name| name_match_patern(hostname, alt_name) }
51
- end
52
-
53
- false
54
- end
55
-
56
- def name_match_patern(hostname, pattern)
57
- re = Regexp.new('\A' + pattern.split('*').map do |st|
58
- Regexp.escape(st)
59
- end.join('[^.]*') + '\z')
60
-
61
- re.match(hostname)
62
- end
63
-
64
- def common_name
65
- certificate.subject.to_a.select { |data| data[0] == 'CN' }.map { |data| data[1] }.first if certificate
36
+ OpenSSL::SSL.verify_certificate_identity(certificate, hostname)
66
37
  end
67
38
  end
68
39
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'resolv'
4
+
5
+ module InternetSecurityEvent
6
+ class TLSAStatus
7
+ attr_reader :record, :certificate
8
+
9
+ def initialize(record, certificate)
10
+ @record = record
11
+ @certificate = certificate
12
+
13
+ @resolv = Resolv::DNS.new
14
+ end
15
+
16
+ def self.build(record, certificate)
17
+ obj = new(record, certificate)
18
+ obj.to_e
19
+ end
20
+
21
+ def to_e
22
+ {
23
+ state: state,
24
+ description: description,
25
+ }
26
+ end
27
+
28
+ def certificate_association_data(selector, matching_type)
29
+ certificate_association_data_digest(certificate_association_data_certificate_bytes(selector), matching_type)
30
+ end
31
+
32
+ def certificate_match_tlsa_record?
33
+ certificate_association_data(record.selector, record.matching_type) == record.certificate_association_data
34
+ end
35
+
36
+ private
37
+
38
+ def certificate_association_data_certificate_bytes(selector)
39
+ case selector
40
+ when Resolv::DNS::Resource::IN::TLSA::Selector::CERT
41
+ certificate.to_der
42
+ when Resolv::DNS::Resource::IN::TLSA::Selector::SPKI
43
+ certificate.public_key.to_der
44
+ end
45
+ end
46
+
47
+ def certificate_association_data_digest(bytes, matching_type)
48
+ case matching_type
49
+ when Resolv::DNS::Resource::IN::TLSA::MatchingType::FULL
50
+ bytes.unpack1('H*')
51
+ when Resolv::DNS::Resource::IN::TLSA::MatchingType::SHA2_256
52
+ Digest::SHA256.hexdigest(bytes)
53
+ when Resolv::DNS::Resource::IN::TLSA::MatchingType::SHA2_512
54
+ Digest::SHA512.hexdigest(bytes)
55
+ end
56
+ end
57
+
58
+ def state
59
+ return 'critical' unless record
60
+
61
+ return nil unless record.end_entity?
62
+
63
+ return 'ok' if certificate_match_tlsa_record?
64
+
65
+ 'critical'
66
+ end
67
+
68
+ def description
69
+ if record.end_entity?
70
+ if certificate_match_tlsa_record?
71
+ 'certificate match TLSA record'
72
+ else
73
+ 'certificate does not match TLSA record'
74
+ end
75
+ else
76
+ # FIXME: For now, we only check the certificate, not the CA
77
+ 'Unsupported certificate usage'
78
+ end
79
+ end
80
+ end
81
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module InternetSecurityEvent
4
- VERSION = '1.0.2'
4
+ VERSION = '1.2.1'
5
5
  end
@@ -1,13 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'action_view'
4
- require 'action_view/helpers'
5
3
  require 'active_support/core_ext/numeric/time'
6
4
 
7
5
  module InternetSecurityEvent
8
6
  class X509Status
9
- include ActionView::Helpers::DateHelper
10
-
11
7
  attr_reader :certificate, :hostname
12
8
 
13
9
  def initialize(certificate)
@@ -19,7 +15,7 @@ module InternetSecurityEvent
19
15
  obj.to_e
20
16
  end
21
17
 
22
- def to_e
18
+ def to_e # rubocop:disable Metrics/AbcSize
23
19
  {
24
20
  state: state,
25
21
  description: description,
@@ -32,6 +28,10 @@ module InternetSecurityEvent
32
28
  }
33
29
  end
34
30
 
31
+ def renewal_duration
32
+ [validity_duration / 3, 90.days].min
33
+ end
34
+
35
35
  private
36
36
 
37
37
  def description
@@ -45,7 +45,7 @@ module InternetSecurityEvent
45
45
  if not_valid_yet? || expired_or_expire_soon?
46
46
  'critical'
47
47
  elsif expire_soonish?
48
- 'warn'
48
+ 'warning'
49
49
  else
50
50
  'ok'
51
51
  end
@@ -71,10 +71,6 @@ module InternetSecurityEvent
71
71
  now + 2 * renewal_duration / 3 > certificate.not_after
72
72
  end
73
73
 
74
- def renewal_duration
75
- [validity_duration / 3, 90.days].min
76
- end
77
-
78
74
  def validity_duration
79
75
  certificate.not_after - certificate.not_before
80
76
  end
@@ -82,5 +78,29 @@ module InternetSecurityEvent
82
78
  def now
83
79
  Now.instance.now
84
80
  end
81
+
82
+ # Stolen from ActionView, to avoid pulling a lot of dependencies
83
+ def distance_of_time_in_words_to_now(to_time) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
84
+ distance_in_seconds = (to_time - now).round.abs
85
+ distance_in_minutes = distance_in_seconds / 60
86
+
87
+ case distance_in_minutes
88
+ when 0 then 'less than 1 minute'
89
+ when 1...45 then pluralize_string('%d minute', distance_in_minutes)
90
+ when 45...1440 then pluralize_string('about %d hour', (distance_in_minutes.to_f / 60.0).round)
91
+ # 24 hours up to 30 days
92
+ when 1440...43_200 then pluralize_string('%d day', (distance_in_minutes.to_f / 1440.0).round)
93
+ # 30 days up to 60 days
94
+ when 43_200...86_400 then pluralize_string('about %d month', (distance_in_minutes.to_f / 43_200.0).round)
95
+ # 60 days up to 365 days
96
+ when 86_400...525_600 then pluralize_string('%d month', (distance_in_minutes.to_f / 43_200.0).round)
97
+ else
98
+ pluralize_string('about %d year', (distance_in_minutes.to_f / 525_600.0).round)
99
+ end
100
+ end
101
+
102
+ def pluralize_string(string, number)
103
+ format(string, number) + (number == 1 ? '' : 's')
104
+ end
85
105
  end
86
106
  end
@@ -2,4 +2,6 @@
2
2
 
3
3
  require 'internet_security_event/now'
4
4
  require 'internet_security_event/tls_status'
5
+ require 'internet_security_event/tlsa_status'
5
6
  require 'internet_security_event/x509_status'
7
+ require 'resolv/dns/resource/in/tlsa'
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Resolv
4
+ class DNS
5
+ class Resource
6
+ module IN
7
+ class TLSA
8
+ module CertificateUsage
9
+ PKIX_TA = 0
10
+ PKIX_EE = 1
11
+ DANE_TA = 2
12
+ DANE_EE = 3
13
+ end
14
+
15
+ module Selector
16
+ CERT = 0
17
+ SPKI = 1
18
+ end
19
+
20
+ module MatchingType
21
+ FULL = 0
22
+ SHA2_256 = 1
23
+ SHA2_512 = 2
24
+ end
25
+
26
+ def initialize(data)
27
+ @certificate_usage, @selector, @matching_type, @certificate_association_data = data.unpack('CCCH*')
28
+ end
29
+
30
+ attr_reader :certificate_usage, :selector, :matching_type, :certificate_association_data
31
+
32
+ def end_entity?
33
+ [CertificateUsage::PKIX_EE, CertificateUsage::DANE_EE].include?(certificate_usage)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: internet_security_event
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Romain Tartière
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-02-21 00:00:00.000000000 Z
11
+ date: 2022-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: actionview
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
@@ -25,21 +25,21 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '5.2'
27
27
  - !ruby/object:Gem::Dependency
28
- name: activesupport
28
+ name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '5.2'
34
- type: :runtime
33
+ version: '0'
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '5.2'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: bundler
42
+ name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake
56
+ name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,35 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rspec
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rspec
71
99
  requirement: !ruby/object:Gem::Requirement
72
100
  requirements:
73
101
  - - ">="
@@ -94,16 +122,18 @@ dependencies:
94
122
  - - ">="
95
123
  - !ruby/object:Gem::Version
96
124
  version: '0'
97
- description:
125
+ description:
98
126
  email:
99
127
  - romain@blogreen.org
100
128
  executables: []
101
129
  extensions: []
102
130
  extra_rdoc_files: []
103
131
  files:
132
+ - ".github/workflows/ci.yml"
104
133
  - ".gitignore"
105
134
  - ".rspec"
106
- - ".travis.yml"
135
+ - ".rubocop.yml"
136
+ - CHANGELOG.md
107
137
  - CODE_OF_CONDUCT.md
108
138
  - Gemfile
109
139
  - LICENSE.txt
@@ -115,13 +145,15 @@ files:
115
145
  - lib/internet_security_event.rb
116
146
  - lib/internet_security_event/now.rb
117
147
  - lib/internet_security_event/tls_status.rb
148
+ - lib/internet_security_event/tlsa_status.rb
118
149
  - lib/internet_security_event/version.rb
119
150
  - lib/internet_security_event/x509_status.rb
151
+ - lib/resolv/dns/resource/in/tlsa.rb
120
152
  homepage: https://github.com/smortex/internet_security_event
121
153
  licenses:
122
154
  - MIT
123
155
  metadata: {}
124
- post_install_message:
156
+ post_install_message:
125
157
  rdoc_options: []
126
158
  require_paths:
127
159
  - lib
@@ -129,16 +161,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
129
161
  requirements:
130
162
  - - ">="
131
163
  - !ruby/object:Gem::Version
132
- version: '0'
164
+ version: 2.6.0
133
165
  required_rubygems_version: !ruby/object:Gem::Requirement
134
166
  requirements:
135
167
  - - ">="
136
168
  - !ruby/object:Gem::Version
137
169
  version: '0'
138
170
  requirements: []
139
- rubyforge_project:
140
- rubygems_version: 2.7.8
141
- signing_key:
171
+ rubygems_version: 3.3.17
172
+ signing_key:
142
173
  specification_version: 4
143
174
  summary: Build events describing the status of various internet services
144
175
  test_files: []
data/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- ---
2
- language: ruby
3
- rvm:
4
- - 2.4
5
- - 2.5
6
- - 2.6
7
- before_script:
8
- - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
9
- - chmod +x ./cc-test-reporter
10
- - ./cc-test-reporter before-build
11
- after_script:
12
- - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT