aboutsummaryrefslogtreecommitdiff
path: root/cvss
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2022-02-16 03:08:44 -0500
committerPaul Duncan <pabs@pablotron.org>2022-02-16 03:08:44 -0500
commit47d25cba0fa216342ce3cc5f1cb3a8bd8d17c824 (patch)
treea08684e71f6ca980cab1ebfcb3bc547bfe52010b /cvss
parent093cc60affd28717f762da672fc6ee8b48d67372 (diff)
downloadcvez-47d25cba0fa216342ce3cc5f1cb3a8bd8d17c824.tar.bz2
cvez-47d25cba0fa216342ce3cc5f1cb3a8bd8d17c824.zip
cvss: 100% v31vector test coverage
Diffstat (limited to 'cvss')
-rw-r--r--cvss/v31vector.go448
-rw-r--r--cvss/v31vector_test.go130
-rw-r--r--cvss/v3metric.go21
-rw-r--r--cvss/v3metric_string.go47
-rw-r--r--cvss/v3metric_test.go18
5 files changed, 408 insertions, 256 deletions
diff --git a/cvss/v31vector.go b/cvss/v31vector.go
index b191ce0..1950e5a 100644
--- a/cvss/v31vector.go
+++ b/cvss/v31vector.go
@@ -131,218 +131,257 @@ func hasTemporalScoreKeys(keys map[Key]v3Metric) bool {
(rc_ok && rc != v3RCNotDefined)
}
+// Does the map have at least one of the keys needed for an env score to
+// be defined?
+func hasEnvScoreKeys(keys map[Key]v3Metric) bool {
+ mav, mav_ok := keys[v3ModifiedAttackVector] // MAV
+ mac, mac_ok := keys[v3ModifiedAttackComplexity] // MAC
+ mpr, mpr_ok := keys[v3ModifiedPrivilegesRequired] // MPR
+ mui, mui_ok := keys[v3ModifiedUserInteraction] // MUI
+ ms, ms_ok := keys[v3ModifiedScope] // MS
+ mc, mc_ok := keys[v3ModifiedConfidentiality] // MC
+ mi, mi_ok := keys[v3ModifiedIntegrity] // MI
+ ma, ma_ok := keys[v3ModifiedAvailability] // MA
+ cr, cr_ok := keys[v3ConfidentialityRequirement] // CR
+ ir, ir_ok := keys[v3IntegrityRequirement] // IR
+ ar, ar_ok := keys[v3AvailabilityRequirement] // AR
+
+ return (mav_ok && mav != v3MAVNotDefined) ||
+ (mac_ok && mac != v3MACNotDefined) ||
+ (mpr_ok && mpr != v3MPRNotDefined) ||
+ (mui_ok && mui != v3MUINotDefined) ||
+ (ms_ok && ms != v3MSNotDefined) ||
+ (mc_ok && mc != v3MCNotDefined) ||
+ (mi_ok && mi != v3MINotDefined) ||
+ (ma_ok && ma != v3MANotDefined) ||
+ (cr_ok && cr != v3CRNotDefined) ||
+ (ir_ok && ir != v3IRNotDefined) ||
+ (ar_ok && ar != v3ARNotDefined);
+}
+
// roundup implemention (from CVSS v3.1 spec, appendix A)
func roundup(val float64) float64 {
return math.Ceil(10.0 * val) / 10.0
}
+var v31MetricCoefs = map[v3Metric]float64 {
+ v3AVNetwork: 0.85, // AV:N
+ v3AVAdjacentNetwork: 0.62, // AV:A
+ v3AVLocal: 0.55, // AV:L
+ v3AVPhysical: 0.2, // AV:P
+
+ v3ACLow: 0.77, // AC:L
+ v3ACHigh: 0.44, // AC:H
+
+ v3PRNone: 0.85, // PR:N
+ v3PRLow: 0.62, // PR:L
+ v3PRHigh: 0.27, // PR:H
+
+ v3UINone: 0.85, // UI:N
+ v3UIRequired: 0.62, // UI:R
+
+ v3CHigh: 0.56, // C:H
+ v3CLow: 0.22, // C:L
+ v3CNone: 0.0, // C:N
+
+ v3IHigh: 0.56, // I:H
+ v3ILow: 0.22, // I:L
+ v3INone: 0.0, // I:N
+
+ v3AHigh: 0.56, // A:H
+ v3ALow: 0.22, // A:L
+ v3ANone: 0.0, // A:N
+
+ v3ENotDefined: 1.0, // E:X
+ v3EHigh: 1.0, // E:H
+ v3EFunctional: 0.97, // E:F
+ v3EProofOfConcept: 0.94, // E:P
+ v3EUnproven: 0.91, // E:U
+
+ v3RLNotDefined: 1.0, // RL:X
+ v3RLUnavailable: 1.0, // RL:U
+ v3RLWorkaround: 0.97, // RL:W
+ v3RLTemporaryFix: 0.96, // RL:T
+ v3RLOfficialFix: 0.95, // RL:O
+
+ v3RCNotDefined: 1.0, // RC:X
+ v3RCConfirmed: 1.0, // RC:C
+ v3RCReasonable: 0.96, // RC:R
+ v3RCUnknown: 0.92, // RC:U
+
+ v3CRNotDefined: 1.0, // CR:X
+ v3CRHigh: 1.5, // CR:H
+ v3CRMedium: 1.0, // CR:M
+ v3CRLow: 0.5, // CR:L
+
+ v3IRNotDefined: 1.0, // IR:X
+ v3IRHigh: 1.5, // IR:H
+ v3IRMedium: 1.0, // IR:M
+ v3IRLow: 0.5, // IR:L
+
+ v3ARNotDefined: 1.0, // AR:X
+ v3ARHigh: 1.5, // AR:H
+ v3ARMedium: 1.0, // AR:M
+ v3ARLow: 0.5, // AR:L
+
+ v3MAVNotDefined: 1.0, // MAV:X
+ v3MAVNetwork: 0.85, // MAV:N
+ v3MAVAdjacentNetwork: 0.62, // MAV:A
+ v3MAVLocal: 0.55, // MAV:L
+ v3MAVPhysical: 0.2, // MAV:P
+
+ v3MACNotDefined: 1.0, // MAC:X
+ v3MACLow: 0.77, // MAC:L
+ v3MACHigh: 0.44, // MAC:H
+
+ v3MPRNotDefined: 1.0, // MPR:X
+ v3MPRNone: 0.85, // MPR:N
+ v3MPRLow: 0.62, // MPR:L
+ v3MPRHigh: 0.27, // MPR:H
+
+ v3MUINotDefined: 1.0, // MUI:X
+ v3MUINone: 0.85, // MUI:N
+ v3MUIRequired: 0.62, // MUI:R
+
+ v3MCNotDefined: 1.0, // MC:X
+ v3MCHigh: 0.56, // MC:H
+ v3MCLow: 0.22, // MC:L
+ v3MCNone: 0.0, // MC:N
+
+ v3MINotDefined: 1.0, // MI:X
+ v3MIHigh: 0.56, // MI:H
+ v3MILow: 0.22, // MI:L
+ v3MINone: 0.0, // MI:N
+
+ v3MANotDefined: 1.0, // MA:X
+ v3MAHigh: 0.56, // MA:H
+ v3MALow: 0.22, // MA:L
+ v3MANone: 0.0, // MA:N
+}
+
+// map of modified metrics to not defined value and base key
+var v31ModMetricDefaults = map[v3Key]struct {
+ notDefined v3Metric
+ baseKey v3Key
+} {
+ v3ModifiedAttackVector: { v3MAVNotDefined, v3AttackVector },
+ v3ModifiedAttackComplexity: { v3MACNotDefined, v3AttackComplexity },
+ v3ModifiedUserInteraction: { v3MUINotDefined, v3UserInteraction },
+ v3ModifiedConfidentiality: { v3MCNotDefined, v3Confidentiality },
+ v3ModifiedIntegrity: { v3MINotDefined, v3Integrity },
+ v3ModifiedAvailability: { v3MANotDefined, v3Availability },
+}
+
+// Get modified metric coefficient, or fall back to base coefficient if
+// modified metric is not defined.
+func getModCoef(keys map[Key]v3Metric, key v3Key) float64 {
+ d := v31ModMetricDefaults[key]
+ if v, _ := keys[key]; v != d.notDefined {
+ // return modified metric coefficient
+ return v31MetricCoefs[v]
+ } else {
+ // return base coefficient
+ return v31MetricCoefs[keys[d.baseKey]]
+ }
+}
+// var metricWeightMPR = CVSS31.Weight.PR [MS !== "X" ? MS : S] [MPR !== "X" ? MPR : PR]; // Depends on MS.
+
+var v31PrivReqCoefs = map[v3Metric]map[bool]float64 {
+ v3PRNone: map[bool]float64 { false: 0.85, true: 0.85 },
+ v3PRLow: map[bool]float64 { false: 0.62, true: 0.68 },
+ v3PRHigh: map[bool]float64 { false: 0.27, true: 0.50 },
+ v3MPRNone: map[bool]float64 { false: 0.85, true: 0.85 },
+ v3MPRLow: map[bool]float64 { false: 0.62, true: 0.68 },
+ v3MPRHigh: map[bool]float64 { false: 0.27, true: 0.50 },
+}
+
// Return numerical scores for this vector.
func (v v31Vector) Scores() (Scores, error) {
- attackVector := 0.0
- attackComplexity := 0.0
- privsRequired := 0.0
- userInteraction := 0.0
scopeChanged := false
- conf := 0.0
- integ := 0.0
- avail := 0.0
- ecm := 1.0
- remediationLevel := 1.0
- reportConfidence := 1.0
- confReq := 1.0
- availReq := 1.0
- integReq := 1.0
-
- modAttackVector := 0.0
- modAttackComplexity := 0.0
- modPrivsRequired := 0.0
- modUserInteraction := 0.0
modScopeChanged := false
- modConf := 0.0
- modInteg := 0.0
- modAvail := 0.0
- keys := make(map[Key]v3Metric)
+ // default metrics map
+ keys := map[Key]v3Metric {
+ v3ExploitCodeMaturity: v3ENotDefined,
+ v3RemediationLevel: v3RLNotDefined,
+ v3ReportConfidence: v3RCNotDefined,
+ v3ConfidentialityRequirement: v3CRNotDefined,
+ v3IntegrityRequirement: v3IRNotDefined,
+ v3AvailabilityRequirement: v3ARNotDefined,
+ v3ModifiedAttackVector: v3MAVNotDefined,
+ v3ModifiedAttackComplexity: v3MACNotDefined,
+ v3ModifiedPrivilegesRequired: v3MPRNotDefined,
+ v3ModifiedUserInteraction: v3MUINotDefined,
+ v3ModifiedConfidentiality: v3MCNotDefined,
+ v3ModifiedIntegrity: v3MINotDefined,
+ v3ModifiedAvailability: v3MANotDefined,
+ v3ModifiedScope: v3MSNotDefined,
+ }
+ // populate metrics map
for _, m := range([]v3Metric(v)) {
keys[m.Key()] = m
switch m {
- case v3AVNetwork: // AV:N
- attackVector = 0.85
- case v3AVAdjacentNetwork: // AV:A
- attackVector = 0.62
- case v3AVLocal: // AV:L
- attackVector = 0.55
- case v3AVPhysical: // AV:P
- attackVector = 0.2
-
- case v3ACLow: // AC:L
- attackComplexity = 0.77
- case v3ACHigh: // AC:H
- attackComplexity = 0.44
-
- case v3PRNone: // PR:N
- privsRequired = 0.85
- case v3PRLow: // PR:L
- privsRequired = 0.62
- case v3PRHigh: // PR:H
- privsRequired = 0.27
-
- case v3UINone: // UI:N
- userInteraction = 0.85
- case v3UIRequired: // UI:R
- userInteraction = 0.62
-
case v3SUnchanged: // S:U
scopeChanged = false
case v3SChanged: // S:C
scopeChanged = true
- case v3CHigh: // C:H
- conf = 0.56
- case v3CLow: // C:L
- conf = 0.22
- case v3CNone: // C:N
- conf = 0.0
-
- case v3IHigh: // I:H
- integ = 0.56
- case v3ILow: // I:L
- integ = 0.22
- case v3INone: // I:N
- integ = 0.0
-
- case v3AHigh: // A:H
- avail = 0.56
- case v3ALow: // A:L
- avail = 0.22
- case v3ANone: // A:N
- avail = 0.0
-
- case v3ENotDefined: // E:X
- ecm = 1.0
- case v3EHigh: // E:H
- ecm = 1.0
- case v3EFunctional: // E:F
- ecm = 0.97
- case v3EProofOfConcept: // E:P
- ecm = 0.94
- case v3EUnproven: // E:U
- ecm = 0.91
-
- case v3RLNotDefined: // RL:X
- remediationLevel = 1.0
- case v3RLUnavailable: // RL:U
- remediationLevel = 1.0
- case v3RLWorkaround: // RL:W
- remediationLevel = 0.97
- case v3RLTemporaryFix: // RL:T
- remediationLevel = 0.96
- case v3RLOfficialFix: // RL:O
- remediationLevel = 0.95
-
- case v3RCNotDefined: // RC:X
- reportConfidence = 1.0
- case v3RCConfirmed: // RC:C
- reportConfidence = 1.0
- case v3RCReasonable: // RC:R
- reportConfidence = 0.96
- case v3RCUnknown: // RC:U
- reportConfidence = 0.92
-
- case v3CRNotDefined: // CR:X
- confReq = 1.0
- case v3CRHigh: // CR:H
- confReq = 1.5
- case v3CRMedium: // CR:M
- confReq = 1.0
- case v3CRLow: // CR:L
- confReq = 0.5
-
- case v3IRNotDefined: // IR:X
- integReq = 1.0
- case v3IRHigh: // IR:H
- integReq = 1.5
- case v3IRMedium: // IR:M
- integReq = 1.0
- case v3IRLow: // IR:L
- integReq = 0.5
-
- case v3ARNotDefined: // AR:X
- availReq = 1.0
- case v3ARHigh: // AR:H
- availReq = 1.5
- case v3ARMedium: // AR:M
- availReq = 1.0
- case v3ARLow: // AR:L
- availReq = 0.5
-
- case v3MAVNotDefined: // MAV:X
- modAttackVector = 0.0
- case v3MAVNetwork: // MAV:N
- modAttackVector = 0.85
- case v3MAVAdjacentNetwork: // MAV:A
- modAttackVector = 0.62
- case v3MAVLocal: // MAV:L
- modAttackVector = 0.55
- case v3MAVPhysical: // MAV:P
- modAttackVector = 0.2
-
- case v3MACNotDefined: // MAC:X
- modAttackComplexity = 0.0
- case v3MACLow: // MAC:L
- modAttackComplexity = 0.77
- case v3MACHigh: // MAC:H
- modAttackComplexity = 0.44
-
- case v3MPRNotDefined: // MPR:X
- modPrivsRequired = 0.0
- case v3MPRLow: // MPR:L
- modPrivsRequired = 0.62
- case v3MPRHigh: // MPR:H
- modPrivsRequired = 0.27
-
- case v3MUINotDefined: // MUI:X
- modUserInteraction = 0.85
- case v3MUINone: // MUI:N
- modUserInteraction = 0.85
- case v3MUIRequired: // MUI:R
- modUserInteraction = 0.62
-
- case v3MSNotDefined: // MS:X
- modScopeChanged = false
case v3MSUnchanged: // MS:U
modScopeChanged = false
- case v3MSChanged: // MS:C
+ case v3MSChanged: // MS:U
modScopeChanged = true
+ }
+ }
- case v3MCNotDefined: // MC:X
- modConf = 0.0
- case v3MCHigh: // MC:H
- modConf = 0.56
- case v3MCLow: // MC:L
- modConf = 0.22
- case v3MCNone: // MC:N
- modConf = 0.0
-
- case v3MINotDefined: // MI:X
- modInteg = 0.0
- case v3MIHigh: // MI:H
- modInteg = 0.56
- case v3MILow: // MI:L
- modInteg = 0.22
- case v3MINone: // MI:N
- modInteg = 0.0
-
- case v3MANotDefined: // MA:X
- modAvail = 0.0
- case v3MAHigh: // MA:H
- modAvail = 0.56
- case v3MALow: // MA:L
- modAvail = 0.22
- case v3MANone: // MA:N
- modAvail = 0.0
+ attackVector := v31MetricCoefs[keys[v3AttackVector]]
+ attackComplexity := v31MetricCoefs[keys[v3AttackComplexity]]
+ userInteraction := v31MetricCoefs[keys[v3UserInteraction]]
+ conf := v31MetricCoefs[keys[v3Confidentiality]]
+ integ := v31MetricCoefs[keys[v3Integrity]]
+ avail := v31MetricCoefs[keys[v3Availability]]
+ ecm := v31MetricCoefs[keys[v3ExploitCodeMaturity]]
+ remediationLevel := v31MetricCoefs[keys[v3RemediationLevel]]
+ reportConfidence := v31MetricCoefs[keys[v3ReportConfidence]]
+ confReq := v31MetricCoefs[keys[v3ConfidentialityRequirement]]
+ availReq := v31MetricCoefs[keys[v3AvailabilityRequirement]]
+ integReq := v31MetricCoefs[keys[v3IntegrityRequirement]]
+
+ // adjust privsRequired based on scopeChanged
+ // (CVSS v3.1 spec, section 7.4, table 16)
+ privsRequired := v31PrivReqCoefs[keys[v3PrivilegesRequired]][scopeChanged]
+
+ modAttackVector := getModCoef(keys, v3ModifiedAttackVector)
+ modAttackComplexity := getModCoef(keys, v3ModifiedAttackComplexity)
+ modUserInteraction := getModCoef(keys, v3ModifiedUserInteraction)
+ modConf := getModCoef(keys, v3ModifiedConfidentiality)
+ modInteg := getModCoef(keys, v3ModifiedIntegrity)
+ modAvail := getModCoef(keys, v3ModifiedAvailability)
+
+ if v, _ := keys[v3ModifiedScope]; v == v3MSNotDefined {
+ // default to base scopeChanged
+ modScopeChanged = scopeChanged
+ }
+
+ // adjust modPrivsRequired based on scopeChanged
+ // (CVSS v3.1 spec, section 7.4, table 16)
+ modPrivsRequired := 0.0
+ {
+ mpr, _ := keys[v3ModifiedPrivilegesRequired]
+ pr, _ := keys[v3PrivilegesRequired]
+ ms, _ := keys[v3ModifiedScope]
+
+ if mpr != v3MPRNotDefined && ms != v3MSNotDefined {
+ modPrivsRequired = v31PrivReqCoefs[mpr][ms == v3MSChanged]
+ } else if mpr != v3MPRNotDefined && ms == v3MSNotDefined {
+ modPrivsRequired = v31PrivReqCoefs[mpr][scopeChanged]
+ } else if mpr == v3MPRNotDefined && ms != v3MSNotDefined {
+ modPrivsRequired = v31PrivReqCoefs[pr][ms == v3MSChanged]
+ } else {
+ // default to base privsRequired
+ // modPrivsRequired = privsRequired
+ modPrivsRequired = v31PrivReqCoefs[pr][scopeChanged]
}
}
@@ -356,17 +395,6 @@ func (v v31Vector) Scores() (Scores, error) {
impact := 0.0
if scopeChanged {
impact = 7.52 * (iss - 0.029) - 3.25 * math.Pow(iss - 0.02, 15)
-
- // adjust privileges required based on scopeChanged
- // (CVSS v3.1 spec, section 7.4, table 16)
- if pr, ok := keys[v3PrivilegesRequired]; ok {
- switch pr {
- case v3PRLow: // PR:L
- privsRequired = 0.68
- case v3PRHigh: // PR:H
- privsRequired = 0.50
- }
- }
} else {
impact = 6.42 * iss
}
@@ -390,17 +418,9 @@ func (v v31Vector) Scores() (Scores, error) {
}
// environmental score (CVSS v3.1 spec, section 7.3)
- //
- // MISS = Minimum(
- // 1 - [(1 - ConfidentialityRequirement × ModifiedConfidentiality) × (1 - IntegrityRequirement × ModifiedIntegrity) × (1 - AvailabilityRequirement × ModifiedAvailability)],
- // 0.915
- // )
- //
-
- // environmental score (CVSS v3.1 spec, section 7.3)
envScore := 0.0
- {
- // modified impact sub score
+ if hasEnvScoreKeys(keys) {
+ // modified impact sub score (ISC_m)
miss := math.Min(
1 - (1 - confReq * modConf) * (1 - integReq * modInteg) * (1 - availReq * modAvail),
0.915,
@@ -415,18 +435,18 @@ func (v v31Vector) Scores() (Scores, error) {
impact = 6.42 * miss
}
- // modified exploitability
+ // modified exploitability sub score
expl := 8.22 * modAttackVector * modAttackComplexity * modPrivsRequired * modUserInteraction
// calculate env score
- if impact < 0.0 {
+ if impact <= 0.0 {
envScore = 0.0
} else if modScopeChanged {
- // Roundup ( Roundup [Minimum (1.08 × [ModifiedImpact + ModifiedExploitability], 10) ] × ExploitCodeMaturity × RemediationLevel × ReportConfidence)
+ // Roundup(Roundup[Minimum(1.08 × [ModifiedImpact + ModifiedExploitability], 10)] × ExploitCodeMaturity × RemediationLevel × ReportConfidence)
envScore = roundup(roundup(math.Min(1.08 * (impact + expl), 10.0)) * ecm * remediationLevel * reportConfidence)
} else {
- // Roundup ( Roundup [Minimum ([ModifiedImpact + ModifiedExploitability], 10) ] × ExploitCodeMaturity × RemediationLevel × ReportConfidence)
- envScore = roundup(roundup(math.Min((impact * expl), 10.0)) * ecm * remediationLevel * reportConfidence)
+ // Roundup(Roundup[Minimum([ModifiedImpact + ModifiedExploitability], 10) ] × ExploitCodeMaturity × RemediationLevel × ReportConfidence)
+ envScore = roundup(roundup(math.Min((impact + expl), 10.0)) * ecm * remediationLevel * reportConfidence)
}
}
diff --git a/cvss/v31vector_test.go b/cvss/v31vector_test.go
index 519b18a..46e1fde 100644
--- a/cvss/v31vector_test.go
+++ b/cvss/v31vector_test.go
@@ -70,7 +70,7 @@ func TestNewV31Vector(t *testing.T) {
}
func TestIsV31VectorString(t *testing.T) {
- // test non v31 strings
+ // test v31 strings
passTests := []string {
"CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N",
@@ -678,6 +678,134 @@ func TestV31VectorScores(t *testing.T) {
name: "RC:C",
val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/RC:C",
exp: []float64 { 7.3, 7.3, 0.0 },
+ }, {
+ name: "MAV:N",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:N/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "MAV:A",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:A/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 6.3 },
+ }, {
+ name: "MAV:L",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:L/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 5.9 },
+ }, {
+ name: "MAV:P",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:P/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 4.3 },
+ }, {
+ name: "MAC:L",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:L/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "MAC:H",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:H/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 5.6 },
+ }, {
+ name: "MPR:N",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:N/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "MPR:L",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:L/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 6.3 },
+ }, {
+ name: "MPR:H",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:H/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 4.7 },
+ }, {
+ name: "MUI:N",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:N/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "MUI:R",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:R/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 6.3 },
+ }, {
+ name: "MS:U",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:U/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "MS:C",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:C/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 8.3 },
+ }, {
+ name: "MC:N",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:N/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 6.5 },
+ }, {
+ name: "MC:L",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:L/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "MC:H",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:H/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 8.6 },
+ }, {
+ name: "MI:N",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:N/MA:X",
+ exp: []float64 { 7.3, 0.0, 6.5 },
+ }, {
+ name: "MI:L",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:L/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "MI:H",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:H/MA:X",
+ exp: []float64 { 7.3, 0.0, 8.6 },
+ }, {
+ name: "MA:N",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:N",
+ exp: []float64 { 7.3, 0.0, 6.5 },
+ }, {
+ name: "MA:N",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:L",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "MA:H",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:H",
+ exp: []float64 { 7.3, 0.0, 8.6 },
+ }, {
+ name: "CR:L",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:L/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 6.9 },
+ }, {
+ name: "CR:M",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:M/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "CR:H",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:H/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.7 },
+ }, {
+ name: "IR:L",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:L/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 6.9 },
+ }, {
+ name: "IR:M",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:M/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "IR:H",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:H/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.7 },
+ }, {
+ name: "AR:L",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:L/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 6.9 },
+ }, {
+ name: "AR:M",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:M/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.3 },
+ }, {
+ name: "AR:H",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:H/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 7.7 },
+ }, {
+ name: "MPR:H/MS:C",
+ val: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:H/MUI:X/MS:C/MC:X/MI:X/MA:X",
+ exp: []float64 { 7.3, 0.0, 6.6 },
}}
for _, test := range(tests) {
diff --git a/cvss/v3metric.go b/cvss/v3metric.go
index df408fd..c0f00be 100644
--- a/cvss/v3metric.go
+++ b/cvss/v3metric.go
@@ -79,6 +79,7 @@ const (
v3MACHigh // MAC:H
v3MPRNotDefined // MPR:X
+ v3MPRNone // MPR:N
v3MPRLow // MPR:L
v3MPRHigh // MPR:H
@@ -86,9 +87,9 @@ const (
v3MUINone // MUI:N
v3MUIRequired // MUI:R
- v3MSNotDefined // MMS:X
- v3MSUnchanged // MMS:U
- v3MSChanged // MMS:C
+ v3MSNotDefined // MS:X
+ v3MSUnchanged // MS:U
+ v3MSChanged // MS:C
v3MCNotDefined // MC:X
v3MCHigh // MC:H
@@ -183,6 +184,7 @@ var v3KeyLut = map[v3Metric]v3Key {
v3MACHigh: v3ModifiedAttackComplexity, // MAC:H
v3MPRNotDefined: v3ModifiedPrivilegesRequired, // MPR:X
+ v3MPRNone: v3ModifiedPrivilegesRequired, // MPR:N
v3MPRLow: v3ModifiedPrivilegesRequired, // MPR:L
v3MPRHigh: v3ModifiedPrivilegesRequired, // MPR:H
@@ -190,9 +192,9 @@ var v3KeyLut = map[v3Metric]v3Key {
v3MUINone: v3ModifiedUserInteraction, // MUI:N
v3MUIRequired: v3ModifiedUserInteraction, // MUI:R
- v3MSNotDefined: v3ModifiedScope, // MMS:X
- v3MSUnchanged: v3ModifiedConfidentiality, // MMS:U
- v3MSChanged: v3ModifiedIntegrity, // MMS:C
+ v3MSNotDefined: v3ModifiedScope, // MS:X
+ v3MSUnchanged: v3ModifiedScope, // MS:U
+ v3MSChanged: v3ModifiedScope, // MS:C
v3MCNotDefined: v3ModifiedConfidentiality, // MC:X
v3MCHigh: v3ModifiedConfidentiality, // MC:H
@@ -285,6 +287,7 @@ var v3MetricStrLut = map[string]v3Metric {
"MAC:H": v3MACHigh,
"MPR:X": v3MPRNotDefined,
+ "MPR:N": v3MPRNone,
"MPR:L": v3MPRLow,
"MPR:H": v3MPRHigh,
@@ -292,9 +295,9 @@ var v3MetricStrLut = map[string]v3Metric {
"MUI:N": v3MUINone,
"MUI:R": v3MUIRequired,
- "MMS:X": v3MSNotDefined,
- "MMS:U": v3MSUnchanged,
- "MMS:C": v3MSChanged,
+ "MS:X": v3MSNotDefined,
+ "MS:U": v3MSUnchanged,
+ "MS:C": v3MSChanged,
"MC:X": v3MCNotDefined,
"MC:H": v3MCHigh,
diff --git a/cvss/v3metric_string.go b/cvss/v3metric_string.go
index b7d6702..6435c57 100644
--- a/cvss/v3metric_string.go
+++ b/cvss/v3metric_string.go
@@ -65,32 +65,33 @@ func _() {
_ = x[v3MACLow-54]
_ = x[v3MACHigh-55]
_ = x[v3MPRNotDefined-56]
- _ = x[v3MPRLow-57]
- _ = x[v3MPRHigh-58]
- _ = x[v3MUINotDefined-59]
- _ = x[v3MUINone-60]
- _ = x[v3MUIRequired-61]
- _ = x[v3MSNotDefined-62]
- _ = x[v3MSUnchanged-63]
- _ = x[v3MSChanged-64]
- _ = x[v3MCNotDefined-65]
- _ = x[v3MCHigh-66]
- _ = x[v3MCLow-67]
- _ = x[v3MCNone-68]
- _ = x[v3MINotDefined-69]
- _ = x[v3MIHigh-70]
- _ = x[v3MILow-71]
- _ = x[v3MINone-72]
- _ = x[v3MANotDefined-73]
- _ = x[v3MAHigh-74]
- _ = x[v3MALow-75]
- _ = x[v3MANone-76]
- _ = x[v3InvalidMetric-77]
+ _ = x[v3MPRNone-57]
+ _ = x[v3MPRLow-58]
+ _ = x[v3MPRHigh-59]
+ _ = x[v3MUINotDefined-60]
+ _ = x[v3MUINone-61]
+ _ = x[v3MUIRequired-62]
+ _ = x[v3MSNotDefined-63]
+ _ = x[v3MSUnchanged-64]
+ _ = x[v3MSChanged-65]
+ _ = x[v3MCNotDefined-66]
+ _ = x[v3MCHigh-67]
+ _ = x[v3MCLow-68]
+ _ = x[v3MCNone-69]
+ _ = x[v3MINotDefined-70]
+ _ = x[v3MIHigh-71]
+ _ = x[v3MILow-72]
+ _ = x[v3MINone-73]
+ _ = x[v3MANotDefined-74]
+ _ = x[v3MAHigh-75]
+ _ = x[v3MALow-76]
+ _ = x[v3MANone-77]
+ _ = x[v3InvalidMetric-78]
}
-const _v3Metric_name = "AV:NAV:AAV:LAV:PAC:LAC:HPR:NPR:LPR:HUI:NUI:RS:US:CC:HC:LC:NI:HI:LI:NA:HA:LA:NE:XE:HE:FE:PE:URL:XRL:URL:WRL:TRL:ORC:XRC:CRC:RRC:UCR:XCR:HCR:MCR:LIR:XIR:HIR:MIR:LAR:XAR:HAR:MAR:LMAV:XMAV:NMAV:AMAV:LMAV:PMAC:XMAC:LMAC:HMPR:XMPR:LMPR:HMUI:XMUI:NMUI:RMMS:XMMS:UMMS:CMC:XMC:HMC:LMC:NMI:XMI:HMI:LMI:NMA:XMA:HMA:LMA:Ninvalid"
+const _v3Metric_name = "AV:NAV:AAV:LAV:PAC:LAC:HPR:NPR:LPR:HUI:NUI:RS:US:CC:HC:LC:NI:HI:LI:NA:HA:LA:NE:XE:HE:FE:PE:URL:XRL:URL:WRL:TRL:ORC:XRC:CRC:RRC:UCR:XCR:HCR:MCR:LIR:XIR:HIR:MIR:LAR:XAR:HAR:MAR:LMAV:XMAV:NMAV:AMAV:LMAV:PMAC:XMAC:LMAC:HMPR:XMPR:NMPR:LMPR:HMUI:XMUI:NMUI:RMS:XMS:UMS:CMC:XMC:HMC:LMC:NMI:XMI:HMI:LMI:NMA:XMA:HMA:LMA:Ninvalid"
-var _v3Metric_index = [...]uint16{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 181, 186, 191, 196, 201, 206, 211, 216, 221, 226, 231, 236, 241, 246, 251, 256, 261, 265, 269, 273, 277, 281, 285, 289, 293, 297, 301, 305, 309, 316}
+var _v3Metric_index = [...]uint16{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 181, 186, 191, 196, 201, 206, 211, 216, 221, 226, 231, 236, 241, 246, 251, 255, 259, 263, 267, 271, 275, 279, 283, 287, 291, 295, 299, 303, 307, 311, 318}
func (i v3Metric) String() string {
if i >= v3Metric(len(_v3Metric_index)-1) {
diff --git a/cvss/v3metric_test.go b/cvss/v3metric_test.go
index a3c587a..40cdec1 100644
--- a/cvss/v3metric_test.go
+++ b/cvss/v3metric_test.go
@@ -88,9 +88,9 @@ func TestGetV3Metric(t *testing.T) {
{ "MUI:N", v3MUINone, true },
{ "MUI:R", v3MUIRequired, true },
- { "MMS:X", v3MSNotDefined, true },
- { "MMS:U", v3MSUnchanged, true },
- { "MMS:C", v3MSChanged, true },
+ { "MS:X", v3MSNotDefined, true },
+ { "MS:U", v3MSUnchanged, true },
+ { "MS:C", v3MSChanged, true },
{ "MC:X", v3MCNotDefined, true },
{ "MC:H", v3MCHigh, true },
@@ -209,9 +209,9 @@ func TestGetV3MetricKey(t *testing.T) {
{ v3MUINone, v3ModifiedUserInteraction }, // MUI:N
{ v3MUIRequired, v3ModifiedUserInteraction }, // MUI:R
- { v3MSNotDefined, v3ModifiedScope }, // MMS:X
- { v3MSUnchanged, v3ModifiedConfidentiality }, // MMS:U
- { v3MSChanged, v3ModifiedIntegrity }, // MMS:C
+ { v3MSNotDefined, v3ModifiedScope }, // MS:X
+ { v3MSUnchanged, v3ModifiedScope }, // MS:U
+ { v3MSChanged, v3ModifiedScope }, // MS:C
{ v3MCNotDefined, v3ModifiedConfidentiality }, // MC:X
{ v3MCHigh, v3ModifiedConfidentiality }, // MC:H
@@ -324,9 +324,9 @@ func TestV3MetricString(t *testing.T) {
{ v3MUINone, "MUI:N" },
{ v3MUIRequired, "MUI:R" },
- { v3MSNotDefined, "MMS:X" },
- { v3MSUnchanged, "MMS:U" },
- { v3MSChanged, "MMS:C" },
+ { v3MSNotDefined, "MS:X" },
+ { v3MSUnchanged, "MS:U" },
+ { v3MSChanged, "MS:C" },
{ v3MCNotDefined, "MC:X" },
{ v3MCHigh, "MC:H" },