cvss2/score.go (73 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cvss2 import ( "fmt" "math" ) func roundTo1Decimal(x float64) float64 { return math.Round(x*10) / 10 } // Validate should be called before calculating any scores on vector // If there's an error, there's no guarantee that a call to *Score() won't panic func (v Vector) Validate() error { switch { case !v.BaseMetrics.AccessVector.defined(): return fmt.Errorf("base metric access vector not defined") case !v.BaseMetrics.AccessComplexity.defined(): return fmt.Errorf("base metric access complexity not defined") case !v.BaseMetrics.Authentication.defined(): return fmt.Errorf("base metric authentication not defined") case !v.BaseMetrics.ConfidentialityImpact.defined(): return fmt.Errorf("base metric confidentiality impact not defined") case !v.BaseMetrics.IntegrityImpact.defined(): return fmt.Errorf("base metric integrity impact not defined") case !v.BaseMetrics.AvailabilityImpact.defined(): return fmt.Errorf("base metric availability impact not defined") default: return nil } } // Score = combined score for the whole Vector func (v Vector) Score() float64 { // combines all of them return v.EnvironmentalScore() } // BaseScore returns base score of the vector func (v Vector) BaseScore() float64 { return v.baseScoreWith(v.impactScore(false)) } // TemporalScore returns temporal score of the vector func (v Vector) TemporalScore() float64 { return v.temporalScoreWith(v.impactScore(false), false) } // EnvironmentalScore returns environmental score of the vector func (v Vector) EnvironmentalScore() float64 { ai := math.Min(10, v.impactScore(true)) at := v.temporalScoreWith(ai, true) return roundTo1Decimal((at + (10-at)*v.EnvironmentalMetrics.CollateralDamagePotential.weight()) * v.EnvironmentalMetrics.TargetDistribution.weight()) } // helpers func (v Vector) impactScore(adjust bool) float64 { c := v.BaseMetrics.ConfidentialityImpact.weight() i := v.BaseMetrics.IntegrityImpact.weight() a := v.BaseMetrics.AvailabilityImpact.weight() if adjust { c *= v.EnvironmentalMetrics.ConfidentialityRequirement.weight() i *= v.EnvironmentalMetrics.IntegrityRequirement.weight() a *= v.EnvironmentalMetrics.AvailabilityRequirement.weight() } return 10.41 * (1 - (1-c)*(1-i)*(1-a)) } func (v Vector) temporalScoreWith(impact float64, envTemporalExtension bool) float64 { e := v.TemporalMetrics.Exploitablity.weight() rl := v.TemporalMetrics.RemediationLevel.weight() rc := v.TemporalMetrics.ReportConfidence.weight() if envTemporalExtension && v.EnvironmentalMetrics.ModifiedExploitablity.defined() { e = v.EnvironmentalMetrics.ModifiedExploitablity.weight() } if envTemporalExtension && v.EnvironmentalMetrics.ModifiedRemediationLevel.defined() { rl = v.EnvironmentalMetrics.ModifiedRemediationLevel.weight() } if envTemporalExtension && v.EnvironmentalMetrics.ModifiedReportConfidence.defined() { rc = v.EnvironmentalMetrics.ModifiedReportConfidence.weight() } return roundTo1Decimal(v.baseScoreWith(impact) * e * rl * rc) } func (v Vector) baseScoreWith(impact float64) float64 { if impact == 0.0 { return 0.0 } exploitability := 20 * v.BaseMetrics.AccessVector.weight() * v.BaseMetrics.AccessComplexity.weight() * v.BaseMetrics.Authentication.weight() return roundTo1Decimal((0.6*impact + 0.4*exploitability - 1.5) * 1.176) }