cvss-suite 1.1.0 → 1.2.2

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.
Files changed (37) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +21 -0
  3. data/.github/ISSUE_TEMPLATE/custom.md +7 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  5. data/.github/workflows/rspec.yml +23 -0
  6. data/.gitignore +1 -0
  7. data/.rubocop.yml +39 -1
  8. data/.rubocop_todo.yml +124 -0
  9. data/CHANGES.md +63 -2
  10. data/PULL_REQUEST_TEMPLATE.md +24 -0
  11. data/README.md +32 -9
  12. data/_config.yml +1 -0
  13. data/bin/console +3 -3
  14. data/cvss_suite.gemspec +14 -13
  15. data/lib/cvss_suite.rb +12 -6
  16. data/lib/cvss_suite/cvss.rb +85 -61
  17. data/lib/cvss_suite/cvss2/cvss2.rb +34 -26
  18. data/lib/cvss_suite/cvss2/cvss2_base.rb +70 -73
  19. data/lib/cvss_suite/cvss2/cvss2_environmental.rb +49 -50
  20. data/lib/cvss_suite/cvss2/cvss2_temporal.rb +41 -39
  21. data/lib/cvss_suite/cvss3/cvss3.rb +34 -26
  22. data/lib/cvss_suite/cvss3/cvss3_base.rb +64 -65
  23. data/lib/cvss_suite/cvss3/cvss3_environmental.rb +159 -107
  24. data/lib/cvss_suite/cvss3/cvss3_temporal.rb +42 -40
  25. data/lib/cvss_suite/cvss31/cvss31.rb +61 -0
  26. data/lib/cvss_suite/cvss31/cvss31_base.rb +94 -0
  27. data/lib/cvss_suite/cvss31/cvss31_environmental.rb +196 -0
  28. data/lib/cvss_suite/cvss31/cvss31_temporal.rb +59 -0
  29. data/lib/cvss_suite/cvss_metric.rb +31 -31
  30. data/lib/cvss_suite/cvss_property.rb +56 -54
  31. data/lib/cvss_suite/helpers/cvss31_helper.rb +27 -0
  32. data/lib/cvss_suite/helpers/cvss3_helper.rb +20 -13
  33. data/lib/cvss_suite/invalid_cvss.rb +31 -32
  34. data/lib/cvss_suite/version.rb +2 -2
  35. metadata +20 -25
  36. data/.travis.yml +0 -4
  37. data/lib/cvss_suite/helpers/extensions.rb +0 -32
@@ -9,7 +9,8 @@
9
9
  # See the LICENSE.md file in the top-level directory.
10
10
 
11
11
  # coding: utf-8
12
- lib = File.expand_path('../lib', __FILE__)
12
+
13
+ lib = File.expand_path('lib', __dir__)
13
14
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
14
15
  require 'cvss_suite/version'
15
16
 
@@ -17,23 +18,23 @@ Gem::Specification.new do |spec|
17
18
  spec.name = 'cvss-suite'
18
19
  spec.version = CvssSuite::VERSION
19
20
  spec.license = 'MIT'
20
- spec.authors = ["Oliver Hamboerger"]
21
- spec.email = ["oliver.hamboerger@siemens.com"]
21
+ spec.authors = ['Oliver Hamboerger']
22
+ spec.email = ['oliver.hamboerger@siemens.com']
22
23
 
23
- spec.summary = %q{Ruby gem for processing cvss vectors.}
24
- spec.description = %q{This Ruby gem helps you to process the vector of the Common Vulnerability Scoring System (https://www.first.org/cvss/specification-document).
25
- Besides calculating the Base, Temporal and Environmental Score, you are able to extract the selected option.}
26
- spec.homepage = "https://siemens.github.io/cvss-suite/"
24
+ spec.summary = 'Ruby gem for processing cvss vectors.'
25
+ spec.description = 'This Ruby gem helps you to process the vector of the Common Vulnerability Scoring System (https://www.first.org/cvss/specification-document).
26
+ Besides calculating the Base, Temporal and Environmental Score, you are able to extract the selected option.'
27
+ spec.homepage = 'https://siemens.github.io/cvss-suite/'
27
28
 
29
+ spec.required_ruby_version = '>= 2.0.0'
28
30
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
29
31
  spec.bindir = 'exe'
30
32
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
33
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
32
- spec.require_paths = ["lib"]
34
+ spec.require_paths = ['lib']
33
35
 
34
- spec.add_development_dependency "bundler", "~> 1.10"
35
- spec.add_development_dependency "rspec", "~> 3.4"
36
- spec.add_development_dependency "rspec-its", "~> 1.2"
37
- spec.add_development_dependency "rdoc", "~> 4.2"
38
- spec.add_development_dependency "simplecov", "~> 0.11.2"
36
+ spec.add_development_dependency 'bundler', '>= 1.10'
37
+ spec.add_development_dependency 'rspec', '~> 3.4'
38
+ spec.add_development_dependency 'rspec-its', '~> 1.2'
39
+ spec.add_development_dependency 'simplecov', '~> 0.11'
39
40
  end
@@ -10,8 +10,8 @@
10
10
 
11
11
  require 'cvss_suite/cvss2/cvss2'
12
12
  require 'cvss_suite/cvss3/cvss3'
13
+ require 'cvss_suite/cvss31/cvss31'
13
14
  require 'cvss_suite/version'
14
- require 'cvss_suite/helpers/extensions'
15
15
  require 'cvss_suite/errors'
16
16
  require 'cvss_suite/invalid_cvss'
17
17
 
@@ -19,19 +19,26 @@ require 'cvss_suite/invalid_cvss'
19
19
  # Module of this gem.
20
20
 
21
21
  module CvssSuite
22
- CVSS_VECTOR_BEGINNINGS = [{:string => 'AV:', :version => 2}, {:string => 'CVSS:3.0/', :version => 3}]
22
+ CVSS_VECTOR_BEGINNINGS = [
23
+ { string: 'AV:', version: 2 },
24
+ { string: 'CVSS:3.0/', version: 3.0 },
25
+ { string: 'CVSS:3.1/', version: 3.1 }
26
+ ]
23
27
 
24
28
  ##
25
29
  # Returns a CVSS class by a +vector+.
26
30
 
27
31
  def self.new(vector)
28
32
  return InvalidCvss.new unless vector.is_a? String
33
+
29
34
  @vector_string = vector
30
35
  case version
31
36
  when 2
32
- Cvss2.new(@vector_string, version)
33
- when 3
34
- Cvss3.new(@vector_string, version)
37
+ Cvss2.new(@vector_string)
38
+ when 3.0
39
+ Cvss3.new(@vector_string)
40
+ when 3.1
41
+ Cvss31.new(@vector_string)
35
42
  else
36
43
  InvalidCvss.new
37
44
  end
@@ -46,5 +53,4 @@ module CvssSuite
46
53
  end
47
54
  end
48
55
  end
49
-
50
56
  end
@@ -11,87 +11,111 @@
11
11
  ##
12
12
  # This class represents any CVSS vector. Do not instantiate this class!
13
13
 
14
- class Cvss
14
+ module CvssSuite
15
+ class Cvss
16
+ ##
17
+ # Metric of a CVSS vector.
15
18
 
16
- ##
17
- # Metric of a CVSS vector.
19
+ attr_reader :base, :temporal, :environmental
18
20
 
19
- attr_reader :base, :temporal, :environmental
21
+ ##
22
+ # Returns the vector itself.
20
23
 
21
- ##
22
- # Returns version of current CVSS vector.
24
+ attr_reader :vector
23
25
 
24
- attr_reader :version
26
+ ##
27
+ # Creates a new CVSS vector by a +vector+.
28
+ #
29
+ # Raises an exception if it is called on Cvss class.
25
30
 
26
- ##
27
- # Returns the vector itself.
31
+ def initialize(vector)
32
+ raise CvssSuite::Errors::InvalidParentClass, 'Do not instantiate this class!' if self.class == Cvss
28
33
 
29
- attr_reader :vector
30
-
31
- ##
32
- # Creates a new CVSS vector by a +vector+ and a +version+.
33
- #
34
- # Raises an exception if it is called on Cvss class.
35
-
36
- def initialize(vector, version)
37
- raise CvssSuite::Errors::InvalidParentClass, 'Do not instantiate this class!' if self.class == Cvss
38
- @version = version
39
- @vector = vector
40
- @properties = []
41
- extract_metrics
42
- init_metrics
43
- end
34
+ @vector = vector
35
+ @properties = []
36
+ extract_metrics
37
+ init_metrics
38
+ end
44
39
 
45
- ##
46
- # Returns if CVSS vector is valid.
40
+ ##
41
+ # Returns if CVSS vector is valid.
47
42
 
48
- def valid?
49
- if @amount_of_properties == required_amount_of_properties
43
+ def valid?
44
+ if @amount_of_properties == required_amount_of_properties
50
45
  base = @base.valid?
51
46
  temporal = @base.valid? && @temporal.valid?
52
47
  environmental = @base.valid? && @environmental.valid?
53
48
  full = @base.valid? && @temporal.valid? && @environmental.valid?
54
49
  base || temporal || environmental || full
55
- else
56
- false
50
+ else
51
+ false
52
+ end
57
53
  end
58
- end
59
54
 
60
- ##
61
- # Returns the Overall Score of the CVSS vector.
55
+ ##
56
+ # Returns the severity of the CVSS vector.
57
+
58
+ def severity
59
+ check_validity
60
+
61
+ score = overall_score
62
+
63
+ if score == 0.0
64
+ 'None'
65
+ elsif (0.1..3.9).include? score
66
+ 'Low'
67
+ elsif (4.0..6.9).include? score
68
+ 'Medium'
69
+ elsif (7.0..8.9).include? score
70
+ 'High'
71
+ elsif (9.0..10.0).include? score
72
+ 'Critical'
73
+ else
74
+ 'None'
75
+ end
76
+ end
62
77
 
63
- def overall_score
64
- check_validity
65
- return temporal_score if @temporal.valid? && !@environmental.valid?
66
- return environmental_score if @environmental.valid?
67
- base_score
68
- end
78
+ ##
79
+ # Returns the Overall Score of the CVSS vector.
69
80
 
70
- private
81
+ def overall_score
82
+ check_validity
83
+ return temporal_score if @temporal.valid? && !@environmental.valid?
84
+ return environmental_score if @environmental.valid?
71
85
 
72
- def extract_metrics
73
- properties = prepared_vector.split('/')
74
- @amount_of_properties = properties.size
75
- properties.each_with_index do |property, index|
76
- property = property.split(':')
77
- @properties.push({ name: property[0], selected: property[1], position: index })
86
+ base_score
78
87
  end
79
- end
80
88
 
81
- def check_validity
82
- raise CvssSuite::Errors::InvalidVector, 'Vector is not valid!' unless valid?
83
- end
89
+ private
84
90
 
85
- def prepared_vector
86
- start_of_vector = @vector.index('AV')
87
- @vector[start_of_vector..-1]
88
- end
91
+ def extract_metrics
92
+ properties = prepared_vector.split('/')
93
+ @amount_of_properties = properties.size
94
+ properties.each_with_index do |property, index|
95
+ property = property.split(':')
96
+ @properties.push({ name: property[0], selected: property[1], position: index })
97
+ end
98
+ end
89
99
 
90
- def required_amount_of_properties
91
- total = @base.count if @base.valid?
92
- total += @temporal.count if @temporal.valid?
93
- total += @environmental.count if @environmental.valid?
94
- total ||= 0
95
- end
100
+ def check_validity
101
+ raise CvssSuite::Errors::InvalidVector, 'Vector is not valid!' unless valid?
102
+ end
103
+
104
+ def prepared_vector
105
+ start_of_vector = @vector.index('AV')
96
106
 
97
- end
107
+ if start_of_vector.nil?
108
+ ''
109
+ else
110
+ @vector[start_of_vector..-1]
111
+ end
112
+ end
113
+
114
+ def required_amount_of_properties
115
+ total = @base.count if @base.valid?
116
+ total += @temporal.count if @temporal.valid?
117
+ total += @environmental.count if @environmental.valid?
118
+ total ||= 0
119
+ end
120
+ end
121
+ end
@@ -8,7 +8,7 @@
8
8
  # This work is licensed under the terms of the MIT license.
9
9
  # See the LICENSE.md file in the top-level directory.
10
10
 
11
- require_relative '../../../lib/cvss_suite/cvss'
11
+ require_relative '../cvss'
12
12
  require_relative 'cvss2_base'
13
13
  require_relative 'cvss2_temporal'
14
14
  require_relative 'cvss2_environmental'
@@ -16,37 +16,45 @@ require_relative 'cvss2_environmental'
16
16
  ##
17
17
  # This class represents a CVSS vector in version 2.
18
18
 
19
- class Cvss2 < Cvss
19
+ module CvssSuite
20
+ class Cvss2 < Cvss
21
+ ##
22
+ # Returns the Version of the CVSS vector.
20
23
 
21
- ##
22
- # Returns the Base Score of the CVSS vector.
24
+ def version
25
+ 2
26
+ end
23
27
 
24
- def base_score
25
- check_validity
26
- @base.score.round(1)
27
- end
28
+ ##
29
+ # Returns the Base Score of the CVSS vector.
28
30
 
29
- ##
30
- # Returns the Temporal Score of the CVSS vector.
31
+ def base_score
32
+ check_validity
33
+ @base.score.round(1)
34
+ end
31
35
 
32
- def temporal_score
33
- (base_score * @temporal.score).round(1)
34
- end
36
+ ##
37
+ # Returns the Temporal Score of the CVSS vector.
35
38
 
36
- ##
37
- # Returns the Environmental Score of the CVSS vector.
39
+ def temporal_score
40
+ (base_score * @temporal.score).round(1)
41
+ end
38
42
 
39
- def environmental_score
40
- return temporal_score unless @environmental.valid?
41
- (@environmental.score @base, @temporal.score).round(1)
42
- end
43
+ ##
44
+ # Returns the Environmental Score of the CVSS vector.
43
45
 
44
- private
46
+ def environmental_score
47
+ return temporal_score unless @environmental.valid?
45
48
 
46
- def init_metrics
47
- @base = Cvss2Base.new(@properties)
48
- @temporal = Cvss2Temporal.new(@properties)
49
- @environmental = Cvss2Environmental.new(@properties)
50
- end
49
+ (@environmental.score @base, @temporal.score).round(1)
50
+ end
51
+
52
+ private
51
53
 
52
- end
54
+ def init_metrics
55
+ @base = Cvss2Base.new(@properties)
56
+ @temporal = Cvss2Temporal.new(@properties)
57
+ @environmental = Cvss2Environmental.new(@properties)
58
+ end
59
+ end
60
+ end
@@ -14,78 +14,75 @@ require_relative '../cvss_metric'
14
14
  ##
15
15
  # This class represents a CVSS Base metric in version 2.
16
16
 
17
- class Cvss2Base < CvssMetric
18
-
19
- ##
20
- # Property of this metric
21
-
22
- attr_reader :access_vector, :access_complexity, :authentication,
23
- :confidentiality_impact, :integrity_impact, :availability_impact
24
-
25
- ##
26
- # Returns the base score of the CVSS vector. The calculation is based on formula version 2.10 .
27
- # See CVSS documentation for further information https://www.first.org/cvss/v2/guide#i3.2.1 .
28
- #
29
- # Takes +Security+ +Requirement+ +Impacts+ for calculating environmental score.
30
-
31
- def score(sr_cr_score = 1, sr_ir_score = 1, sr_ar_score = 1)
32
-
33
- impact = calc_impact sr_cr_score, sr_ir_score, sr_ar_score
34
-
35
- exploitability = calc_exploitability
36
-
37
- additional_impact = (impact == 0 ? 0 : 1.176)
38
-
39
- ((0.6 * impact) + (0.4 * exploitability) - 1.5) * additional_impact
40
-
17
+ module CvssSuite
18
+ class Cvss2Base < CvssMetric
19
+ ##
20
+ # Property of this metric
21
+
22
+ attr_reader :access_vector, :access_complexity, :authentication,
23
+ :confidentiality_impact, :integrity_impact, :availability_impact
24
+
25
+ ##
26
+ # Returns the base score of the CVSS vector. The calculation is based on formula version 2.10 .
27
+ # See CVSS documentation for further information https://www.first.org/cvss/v2/guide#i3.2.1 .
28
+ #
29
+ # Takes +Security+ +Requirement+ +Impacts+ for calculating environmental score.
30
+
31
+ def score(sr_cr_score = 1, sr_ir_score = 1, sr_ar_score = 1)
32
+ impact = calc_impact(sr_cr_score, sr_ir_score, sr_ar_score)
33
+
34
+ exploitability = calc_exploitability
35
+
36
+ additional_impact = (impact == 0 ? 0 : 1.176)
37
+
38
+ ((0.6 * impact) + (0.4 * exploitability) - 1.5) * additional_impact
39
+ end
40
+
41
+ private
42
+
43
+ def init_properties
44
+ @properties.push(@access_vector =
45
+ CvssProperty.new(name: 'Access Vector', abbreviation: 'AV', position: [0],
46
+ choices: [{ name: 'Network', abbreviation: 'N', weight: 1.0 },
47
+ { name: 'Adjacent Network', abbreviation: 'A', weight: 0.646 },
48
+ { name: 'Local', abbreviation: 'L', weight: 0.395 }]))
49
+ @properties.push(@access_complexity =
50
+ CvssProperty.new(name: 'Access Complexity', abbreviation: 'AC', position: [1],
51
+ choices: [{ name: 'Low', abbreviation: 'L', weight: 0.71 },
52
+ { name: 'Medium', abbreviation: 'M', weight: 0.61 },
53
+ { name: 'High', abbreviation: 'H', weight: 0.35 }]))
54
+ @properties.push(@authentication =
55
+ CvssProperty.new(name: 'Authentication', abbreviation: 'Au', position: [2],
56
+ choices: [{ name: 'None', abbreviation: 'N', weight: 0.704 },
57
+ { name: 'Single', abbreviation: 'S', weight: 0.56 },
58
+ { name: 'Multiple', abbreviation: 'M', weight: 0.45 }]))
59
+ @properties.push(@confidentiality_impact =
60
+ CvssProperty.new(name: 'Confidentiality Impact', abbreviation: 'C', position: [3],
61
+ choices: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
62
+ { name: 'Partial', abbreviation: 'P', weight: 0.275 },
63
+ { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
64
+ @properties.push(@integrity_impact =
65
+ CvssProperty.new(name: 'Integrity Impact', abbreviation: 'I', position: [4],
66
+ choices: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
67
+ { name: 'Partial', abbreviation: 'P', weight: 0.275 },
68
+ { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
69
+ @properties.push(@availability_impact =
70
+ CvssProperty.new(name: 'Availability Impact', abbreviation: 'A', position: [5],
71
+ choices: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
72
+ { name: 'Partial', abbreviation: 'P', weight: 0.275 },
73
+ { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
74
+ end
75
+
76
+ def calc_impact(sr_cr_score, sr_ir_score, sr_ar_score)
77
+ confidentiality_score = 1 - @confidentiality_impact.score * sr_cr_score
78
+ integrity_score = 1 - @integrity_impact.score * sr_ir_score
79
+ availability_score = 1 - @availability_impact.score * sr_ar_score
80
+
81
+ [10, 10.41 * (1 - confidentiality_score * integrity_score * availability_score)].min
82
+ end
83
+
84
+ def calc_exploitability
85
+ 20 * @access_vector.score * @access_complexity.score * @authentication.score
86
+ end
41
87
  end
42
-
43
- private
44
-
45
- def init_properties
46
- @properties.push(@access_vector =
47
- CvssProperty.new(name: 'Access Vector', abbreviation: 'AV', position: [0],
48
- choices: [{ name: 'Network', abbreviation: 'N', weight: 1.0 },
49
- { name: 'Adjacent Network', abbreviation: 'A', weight: 0.646 },
50
- { name: 'Local', abbreviation: 'L', weight: 0.395 }]))
51
- @properties.push(@access_complexity =
52
- CvssProperty.new(name: 'Access Complexity', abbreviation: 'AC', position: [1],
53
- choices: [{ name: 'Low', abbreviation: 'L', weight: 0.71 },
54
- { name: 'Medium', abbreviation: 'M', weight: 0.61 },
55
- { name: 'High', abbreviation: 'H', weight: 0.35 }]))
56
- @properties.push(@authentication =
57
- CvssProperty.new(name: 'Authentication', abbreviation: 'Au', position: [2],
58
- choices: [{ name: 'None', abbreviation: 'N', weight: 0.704 },
59
- { name: 'Single', abbreviation: 'S', weight: 0.56 },
60
- { name: 'Multiple', abbreviation: 'M', weight: 0.45 }]))
61
- @properties.push(@confidentiality_impact =
62
- CvssProperty.new(name: 'Confidentiality Impact', abbreviation: 'C', position: [3],
63
- choices: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
64
- { name: 'Partial', abbreviation: 'P', weight: 0.275 },
65
- { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
66
- @properties.push(@integrity_impact =
67
- CvssProperty.new(name: 'Integrity Impact', abbreviation: 'I', position: [4],
68
- choices: [{ name: 'None', abbreviation: 'N', weight: 0.0 },
69
- { name: 'Partial', abbreviation: 'P', weight: 0.275 },
70
- { name: 'Complete', abbreviation: 'C', weight: 0.66 }]))
71
- @properties.push(@availability_impact =
72
- CvssProperty.new(name: 'Availability Impact', abbreviation: 'A', position: [5],
73
- choices: [{ name: 'None', abbreviation: 'N', weight: 0.0},
74
- { name: 'Partial', abbreviation: 'P', weight: 0.275},
75
- { name: 'Complete', abbreviation: 'C', weight: 0.66}]))
76
- end
77
-
78
- def calc_impact(sr_cr_score, sr_ir_score, sr_ar_score)
79
- confidentiality_score = 1 - @confidentiality_impact.score * sr_cr_score
80
- integrity_score = 1 - @integrity_impact.score * sr_ir_score
81
- availability_score = 1 - @availability_impact.score * sr_ar_score
82
-
83
- [10, 10.41 * (1-confidentiality_score*integrity_score*availability_score)].min
84
- end
85
-
86
- def calc_exploitability
87
- 20 * @access_vector.score * @access_complexity.score * @authentication.score
88
- end
89
-
90
88
  end
91
-