aboutsummaryrefslogtreecommitdiff
path: root/cvss/scores.go
diff options
context:
space:
mode:
Diffstat (limited to 'cvss/scores.go')
-rw-r--r--cvss/scores.go266
1 files changed, 266 insertions, 0 deletions
diff --git a/cvss/scores.go b/cvss/scores.go
new file mode 100644
index 0000000..3100b19
--- /dev/null
+++ b/cvss/scores.go
@@ -0,0 +1,266 @@
+package cvss
+
+import (
+ "math"
+)
+
+// CVSS score set.
+type Scores struct {
+ Base Score `json:"base"` // base score
+ Temporal Score `json:"temporal"` // temporal score
+ Env Score `json:"env"` // environmental score
+}
+
+// Create new score set from floats.
+func NewScores(base, temporal, env float64) (Scores, error) {
+ // convert base from float to Score
+ baseScore, err := NewScore(base)
+ if err != nil {
+ return Scores{}, err
+ }
+
+ // convert temporal from float to Score
+ tempScore, err := NewScore(temporal)
+ if err != nil {
+ return Scores{}, err
+ }
+
+ // convert env from float to Score
+ envScore, err := NewScore(env)
+ if err != nil {
+ return Scores{}, err
+ }
+
+ // return success
+ return Scores {
+ Base: baseScore,
+ Temporal: tempScore,
+ Env: envScore,
+ }, nil
+}
+
+// Create new v2 scores from v2 vector.
+func newScoresFromV2Vector(v v2Vector) (Scores, error) {
+ // CVSS v2 (https://www.first.org/cvss/v2/guide 3.2.1)
+ //
+ // Impact = 10.41*(1-(1-ConfImpact)*(1-IntegImpact)*(1-AvailImpact))
+ // Exploitability = 20* AccessVector*AccessComplexity*Authentication
+ // f(impact)= 0 if Impact=0, 1.176 otherwise
+ // BaseScore = round_to_1_decimal(((0.6*Impact)+(0.4*Exploitability)-1.5)*f(Impact))
+
+ // base score values
+ confImpact := 0.0
+ integImpact := 0.0
+ availImpact := 0.0
+ accessVector := 0.0
+ accessComplexity := 0.0
+ auth := 0.0
+
+ // temporal score values
+ // (FIXME: should these be set to 1.0?)
+ exploitability := 0.0
+ remediationLevel := 0.0
+ reportConfidence := 0.0
+
+ // env score values
+ cdp := 0.0
+ td := 0.0
+ confReq := 0.0
+ integReq := 0.0
+ availReq := 0.0
+
+ for _, m := range([]v2Metric(v)) {
+ switch m {
+ case v2AVNetwork: // AV:N
+ accessVector = 1.0
+ case v2AVAdjacentNetwork: // AV:A
+ accessVector = 0.646
+ case v2AVLocal: // AV:L
+ accessVector = 0.395
+
+ case v2ACLow: // AC:L
+ accessComplexity = 0.71
+ case v2ACMedium: // AC:M
+ accessComplexity = 0.61
+ case v2ACHigh: // AC:H
+ accessComplexity = 0.35
+
+ case v2AuMultiple: // Au:M
+ auth = 0.45
+ case v2AuSingle: // Au:S
+ auth = 0.56
+ case v2AuNone: // Au:N
+ auth = 0.704
+
+ case v2CNone: // C:N
+ confImpact = 0.0
+ case v2CPartial: // C:P
+ confImpact = 0.275
+ case v2CComplete: // C:C
+ confImpact = 0.660
+
+ case v2INone: // I:N
+ integImpact = 0.0
+ case v2IPartial: // I:P
+ integImpact = 0.275
+ case v2IComplete: // I:C
+ integImpact = 0.660
+
+ case v2ANone: // A:N
+ availImpact = 0.0
+ case v2APartial: // A:P
+ availImpact = 0.275
+ case v2AComplete: // A:C
+ availImpact = 0.660
+
+ case v2ENotDefined: // E:ND
+ exploitability = 1.0
+ case v2EUnproven: // E:U
+ exploitability = 0.85
+ case v2EProofOfConcept: // E:POC
+ exploitability = 0.9
+ case v2EFunctional: // E:F
+ exploitability = 0.95
+ case v2EHigh: // E:H
+ exploitability = 1.0
+
+ case v2RLOfficialFix: // RL:OF
+ remediationLevel = 0.87
+ case v2RLTemporaryFix: // RL:TF
+ remediationLevel = 0.9
+ case v2RLWorkaround: // RL:W
+ remediationLevel = 0.95
+ case v2RLUnavailable: // RL:U
+ remediationLevel = 1.0
+ case v2RLNotDefined: // RL:ND
+ remediationLevel = 1.0
+
+ case v2RCUnconfirmed: // RC:UC
+ reportConfidence = 0.9
+ case v2RCUncorroborated: // RC:UR
+ reportConfidence = 0.95
+ case v2RCConfirmed: // RC:C
+ reportConfidence = 1.0
+ case v2RCNotDefined: // RC:ND
+ reportConfidence = 1.0
+
+ case v2CDPNone: // CDP:N
+ cdp = 0.0
+ case v2CDPLow: // CDP:L
+ cdp = 0.1
+ case v2CDPLowMedium: // CDP:LM
+ cdp = 0.3
+ case v2CDPMediumHigh: // CDP:MH
+ cdp = 0.4
+ case v2CDPHigh: // CDP:H
+ cdp = 0.5
+ case v2CDPNotDefined: // CDP:ND
+ cdp = 0.0
+
+ case v2TDNone: // TD:N
+ td = 0.0
+ case v2TDLow: // TD:L
+ td = 0.25
+ case v2TDMedium: // TD:M
+ td = 0.75
+ case v2TDHigh: // TD:H
+ td = 1.0
+ case v2TDNotDefined: // TD:ND
+ td = 1.0
+
+ case v2CRLow: // CR:L
+ confReq = 0.5
+ case v2CRMedium: // CR:M
+ confReq = 1.0
+ case v2CRHigh: // CR:H
+ confReq = 1.51
+ case v2CRNotDefined: // CR:ND
+ confReq = 1.0
+
+ case v2IRLow: // IR:L
+ integReq = 0.5
+ case v2IRMedium: // IR:M
+ integReq = 1.0
+ case v2IRHigh: // IR:H
+ integReq = 1.51
+ case v2IRNotDefined: // IR:ND
+ integReq = 1.0
+
+ case v2ARLow: // AR:L
+ availReq = 0.5
+ case v2ARMedium: // AR:M
+ availReq = 1.0
+ case v2ARHigh: // AR:H
+ availReq = 1.51
+ case v2ARNotDefined: // AR:ND
+ availReq = 1.0
+ }
+ }
+
+ // calculate base score (3.2.1 Base Equation)
+ //
+ // Impact = 10.41*(1-(1-ConfImpact)*(1-IntegImpact)*(1-AvailImpact))
+ // Exploitability = 20* AccessVector*AccessComplexity*Authentication
+ // f(impact)= 0 if Impact=0, 1.176 otherwise
+ // BaseScore = round_to_1_decimal(((0.6*Impact)+(0.4*Exploitability)-1.5)*f(Impact))
+ baseScore := 0.0
+ {
+ impact := 10.41 * (1 - (1 - confImpact) * (1 - integImpact) * (1 - availImpact))
+ fImpact := 0.0
+ if impact > 0.0 {
+ fImpact = 1.176
+ }
+ baseExpl := 20 * accessVector * accessComplexity * auth
+ baseScore = ((0.6 * impact + 0.4 * baseExpl) - 1.5) * fImpact
+ baseScore = math.Round(10.0 * baseScore) / 10.0
+ }
+
+ // calculate temporal score (3.2.2 Temporal Equation)
+ //
+ // TemporalScore = round_to_1_decimal(BaseScore*Exploitability
+ // *RemediationLevel*ReportConfidence)
+ tempScore := 0.0
+ {
+ tempScore = baseScore * exploitability * remediationLevel * reportConfidence
+ tempScore = math.Round(10.0 * tempScore) / 10.0
+ }
+
+ // calculate environmental score (3.2.3 Environmental Equation)
+ //
+ // AdjustedImpact = min(10,10.41*(1-(1-ConfImpact*ConfReq)*(1-IntegImpact*IntegReq)
+ // *(1-AvailImpact*AvailReq)))
+ //
+ // AdjustedTemporal = TemporalScore recomputed with the BaseScore's
+ // Impact sub-equation replaced with the AdjustedImpact equation
+ //
+ // EnvironmentalScore = round_to_1_decimal((AdjustedTemporal+
+ // (10-AdjustedTemporal)*CollateralDamagePotential)*TargetDistribution)
+ //
+ envScore := 0.0
+ {
+ // calc adjusted impact
+ adjImpact := math.Min(
+ 10.0,
+ 10.41 * (1 - (1 - confImpact * confReq) * (1 - integImpact * integReq) * (1 - availImpact * availReq)),
+ )
+ fImpact := 0.0
+ if adjImpact > 0.0 {
+ fImpact = 1.176
+ }
+
+ // calculate environmental base score using adjusted impact
+ baseExpl := 20 * accessVector * accessComplexity * auth
+ envBaseScore := ((0.6 * adjImpact + 0.4 * baseExpl) - 1.5) * fImpact
+ envBaseScore = (10.0 * envBaseScore) / 10.0
+
+ // calculate adjusted temporal score
+ adjTempScore := envBaseScore * exploitability * remediationLevel * reportConfidence
+ adjTempScore = math.Round(10.0 * adjTempScore) / 10.0
+
+ envScore = (adjTempScore + (10 - adjTempScore) * cdp) * td
+ envScore = math.Round(10.0 * envScore) / 10.0
+ }
+
+ // build and return result
+ return NewScores(baseScore, tempScore, envScore)
+}