package cvss import ( "math" ) //go:generate stringer -linecomment -type=v3Metric // metric value type v3Metric byte const ( v3AVNetwork v3Metric = iota // AV:N v3AVAdjacentNetwork // AV:A v3AVLocal // AV:L v3AVPhysical // AV:P v3ACLow // AC:L v3ACHigh // AC:H v3PRNone // PR:N v3PRLow // PR:L v3PRHigh // PR:H v3UINone // UI:N v3UIRequired // UI:R v3SUnchanged // S:U v3SChanged // S:C v3CHigh // C:H v3CLow // C:L v3CNone // C:N v3IHigh // I:H v3ILow // I:L v3INone // I:N v3AHigh // A:H v3ALow // A:L v3ANone // A:N v3ENotDefined // E:X v3EHigh // E:H v3EFunctional // E:F v3EProofOfConcept // E:P v3EUnproven // E:U v3RLNotDefined // RL:X v3RLUnavailable // RL:U v3RLWorkaround // RL:W v3RLTemporaryFix // RL:T v3RLOfficialFix // RL:O v3RCNotDefined // RC:X v3RCConfirmed // RC:C v3RCReasonable // RC:R v3RCUnknown // RC:U v3CRNotDefined // CR:X v3CRHigh // CR:H v3CRMedium // CR:M v3CRLow // CR:L v3IRNotDefined // IR:X v3IRHigh // IR:H v3IRMedium // IR:M v3IRLow // IR:L v3ARNotDefined // AR:X v3ARHigh // AR:H v3ARMedium // AR:M v3ARLow // AR:L v3MAVNotDefined // MAV:X v3MAVNetwork // MAV:N v3MAVAdjacentNetwork // MAV:A v3MAVLocal // MAV:L v3MAVPhysical // MAV:P v3MACNotDefined // MAC:X v3MACLow // MAC:L v3MACHigh // MAC:H v3MPRNotDefined // MPR:X v3MPRNone // MPR:N v3MPRLow // MPR:L v3MPRHigh // MPR:H v3MUINotDefined // MUI:X v3MUINone // MUI:N v3MUIRequired // MUI:R v3MSNotDefined // MS:X v3MSUnchanged // MS:U v3MSChanged // MS:C v3MCNotDefined // MC:X v3MCHigh // MC:H v3MCLow // MC:L v3MCNone // MC:N v3MINotDefined // MI:X v3MIHigh // MI:H v3MILow // MI:L v3MINone // MI:N v3MANotDefined // MA:X v3MAHigh // MA:H v3MALow // MA:L v3MANone // MA:N v3InvalidMetric // invalid ) // map of metrics to metric keys var v3KeyLut = map[v3Metric]v3Key { v3AVNetwork: v3AttackVector, // AV:N v3AVAdjacentNetwork: v3AttackVector, // AV:A v3AVLocal: v3AttackVector, // AV:L v3AVPhysical: v3AttackVector, // AV:P v3ACLow: v3AttackComplexity, // AC:L v3ACHigh: v3AttackComplexity, // AC:H v3PRNone: v3PrivilegesRequired, // PR:N v3PRLow: v3PrivilegesRequired, // PR:L v3PRHigh: v3PrivilegesRequired, // PR:H v3UINone: v3UserInteraction, // UI:N v3UIRequired: v3UserInteraction, // UI:R v3SUnchanged: v3Scope, // S:U v3SChanged: v3Scope, // S:C v3CHigh: v3Confidentiality, // C:H v3CLow: v3Confidentiality, // C:L v3CNone: v3Confidentiality, // C:N v3IHigh: v3Integrity, // I:H v3ILow: v3Integrity, // I:L v3INone: v3Integrity, // I:N v3AHigh: v3Availability, // A:H v3ALow: v3Availability, // A:L v3ANone: v3Availability, // A:N v3ENotDefined: v3ExploitCodeMaturity, // E:X v3EHigh: v3ExploitCodeMaturity, // E:H v3EFunctional: v3ExploitCodeMaturity, // E:F v3EProofOfConcept: v3ExploitCodeMaturity, // E:P v3EUnproven: v3ExploitCodeMaturity, // E:U v3RLNotDefined: v3RemediationLevel, // RL:X v3RLUnavailable: v3RemediationLevel, // RL:U v3RLWorkaround: v3RemediationLevel, // RL:W v3RLTemporaryFix: v3RemediationLevel, // RL:T v3RLOfficialFix: v3RemediationLevel, // RL:O v3RCNotDefined: v3ReportConfidence, // RC:X v3RCConfirmed: v3ReportConfidence, // RC:C v3RCReasonable: v3ReportConfidence, // RC:R v3RCUnknown: v3ReportConfidence, // RC:U v3CRNotDefined: v3ConfidentialityRequirement, // CR:X v3CRHigh: v3ConfidentialityRequirement, // CR:H v3CRMedium: v3ConfidentialityRequirement, // CR:M v3CRLow: v3ConfidentialityRequirement, // CR:L v3IRNotDefined: v3IntegrityRequirement, // IR:X v3IRHigh: v3IntegrityRequirement, // IR:H v3IRMedium: v3IntegrityRequirement, // IR:M v3IRLow: v3IntegrityRequirement, // IR:L v3ARNotDefined: v3AvailabilityRequirement, // AR:X v3ARHigh: v3AvailabilityRequirement, // AR:H v3ARMedium: v3AvailabilityRequirement, // AR:M v3ARLow: v3AvailabilityRequirement, // AR:L v3MAVNotDefined: v3ModifiedAttackVector, // MAV:X v3MAVNetwork: v3ModifiedAttackVector, // MAV:N v3MAVAdjacentNetwork: v3ModifiedAttackVector, // MAV:A v3MAVLocal: v3ModifiedAttackVector, // MAV:L v3MAVPhysical: v3ModifiedAttackVector, // MAV:P v3MACNotDefined: v3ModifiedAttackComplexity, // MAC:X v3MACLow: v3ModifiedAttackComplexity, // MAC:L v3MACHigh: v3ModifiedAttackComplexity, // MAC:H v3MPRNotDefined: v3ModifiedPrivilegesRequired, // MPR:X v3MPRNone: v3ModifiedPrivilegesRequired, // MPR:N v3MPRLow: v3ModifiedPrivilegesRequired, // MPR:L v3MPRHigh: v3ModifiedPrivilegesRequired, // MPR:H v3MUINotDefined: v3ModifiedUserInteraction, // MUI:X v3MUINone: v3ModifiedUserInteraction, // MUI:N v3MUIRequired: v3ModifiedUserInteraction, // MUI:R v3MSNotDefined: v3ModifiedScope, // MS:X v3MSUnchanged: v3ModifiedScope, // MS:U v3MSChanged: v3ModifiedScope, // MS:C v3MCNotDefined: v3ModifiedConfidentiality, // MC:X v3MCHigh: v3ModifiedConfidentiality, // MC:H v3MCLow: v3ModifiedConfidentiality, // MC:L v3MCNone: v3ModifiedConfidentiality, // MC:N v3MINotDefined: v3ModifiedIntegrity, // MI:X v3MIHigh: v3ModifiedIntegrity, // MI:H v3MILow: v3ModifiedIntegrity, // MI:L v3MINone: v3ModifiedIntegrity, // MI:N v3MANotDefined: v3ModifiedAvailability, // MA:X v3MAHigh: v3ModifiedAvailability, // MA:H v3MALow: v3ModifiedAvailability, // MA:L v3MANone: v3ModifiedAvailability, // MA:N } // map of metric strings to metrics var v3MetricStrLut = map[string]v3Metric { "AV:N": v3AVNetwork, "AV:A": v3AVAdjacentNetwork, "AV:L": v3AVLocal, "AV:P": v3AVPhysical, "AC:L": v3ACLow, "AC:H": v3ACHigh, "PR:N": v3PRNone, "PR:L": v3PRLow, "PR:H": v3PRHigh, "UI:N": v3UINone, "UI:R": v3UIRequired, "S:U": v3SUnchanged, "S:C": v3SChanged, "C:H": v3CHigh, "C:L": v3CLow, "C:N": v3CNone, "I:H": v3IHigh, "I:L": v3ILow, "I:N": v3INone, "A:H": v3AHigh, "A:L": v3ALow, "A:N": v3ANone, "E:X": v3ENotDefined, "E:H": v3EHigh, "E:F": v3EFunctional, "E:P": v3EProofOfConcept, "E:U": v3EUnproven, "RL:X": v3RLNotDefined, "RL:U": v3RLUnavailable, "RL:W": v3RLWorkaround, "RL:T": v3RLTemporaryFix, "RL:O": v3RLOfficialFix, "RC:X": v3RCNotDefined, "RC:C": v3RCConfirmed, "RC:R": v3RCReasonable, "RC:U": v3RCUnknown, "CR:X": v3CRNotDefined, "CR:H": v3CRHigh, "CR:M": v3CRMedium, "CR:L": v3CRLow, "IR:X": v3IRNotDefined, "IR:H": v3IRHigh, "IR:M": v3IRMedium, "IR:L": v3IRLow, "AR:X": v3ARNotDefined, "AR:H": v3ARHigh, "AR:M": v3ARMedium, "AR:L": v3ARLow, "MAV:X": v3MAVNotDefined, "MAV:N": v3MAVNetwork, "MAV:A": v3MAVAdjacentNetwork, "MAV:L": v3MAVLocal, "MAV:P": v3MAVPhysical, "MAC:X": v3MACNotDefined, "MAC:L": v3MACLow, "MAC:H": v3MACHigh, "MPR:X": v3MPRNotDefined, "MPR:N": v3MPRNone, "MPR:L": v3MPRLow, "MPR:H": v3MPRHigh, "MUI:X": v3MUINotDefined, "MUI:N": v3MUINone, "MUI:R": v3MUIRequired, "MS:X": v3MSNotDefined, "MS:U": v3MSUnchanged, "MS:C": v3MSChanged, "MC:X": v3MCNotDefined, "MC:H": v3MCHigh, "MC:L": v3MCLow, "MC:N": v3MCNone, "MI:X": v3MINotDefined, "MI:H": v3MIHigh, "MI:L": v3MILow, "MI:N": v3MINone, "MA:X": v3MANotDefined, "MA:H": v3MAHigh, "MA:L": v3MALow, "MA:N": v3MANone, } // Get CVSS 3.x metric key. func (m v3Metric) Key() Key { if k, ok := v3KeyLut[m]; ok { return k } else { return v3InvalidKey } } // Convert string to CVSS 3.x metric. func getV3Metric(version Version, s string) (v3Metric, error) { if m, ok := v3MetricStrLut[s]; ok { return m, nil } else { return v3InvalidMetric, newBadMetric(version, s) } } // Does the map have at least one of the keys needed for a temporal // score defined? func hasV3TemporalScoreKeys(keys map[Key]v3Metric) bool { ecm, ecm_ok := keys[v3ExploitCodeMaturity] // E rl, rl_ok := keys[v3RemediationLevel] // RL rc, rc_ok := keys[v3ReportConfidence] // RC return (ecm_ok && ecm != v3ENotDefined) || (rl_ok && rl != v3RLNotDefined) || (rc_ok && rc != v3RCNotDefined) } // Does the map have at least one of the keys needed for an env score to // be defined? func hasV3EnvScoreKeys(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 v3MetricCoefs = 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 v3ModMetricDefaults = 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 getV3ModCoef(keys map[Key]v3Metric, key v3Key) float64 { d := v3ModMetricDefaults[key] if v, _ := keys[key]; v != d.notDefined { // return modified metric coefficient return v3MetricCoefs[v] } else { // return base coefficient return v3MetricCoefs[keys[d.baseKey]] } } var v3PrivReqCoefs = 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 }, }