aboutsummaryrefslogtreecommitdiff
path: root/internal/cvss/cvss.go
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2022-01-31 11:09:58 -0500
committerPaul Duncan <pabs@pablotron.org>2022-01-31 11:09:58 -0500
commitb3dc36421f133ea6983574891720e974cf7974dd (patch)
treec6375903fa820bd0ac64ce40827c2c8302d38737 /internal/cvss/cvss.go
downloadcvez-b3dc36421f133ea6983574891720e974cf7974dd.tar.bz2
cvez-b3dc36421f133ea6983574891720e974cf7974dd.zip
initial commit
Diffstat (limited to 'internal/cvss/cvss.go')
-rw-r--r--internal/cvss/cvss.go926
1 files changed, 926 insertions, 0 deletions
diff --git a/internal/cvss/cvss.go b/internal/cvss/cvss.go
new file mode 100644
index 0000000..e50f718
--- /dev/null
+++ b/internal/cvss/cvss.go
@@ -0,0 +1,926 @@
+// CVSS vector parser.
+package cvss
+
+import (
+ "fmt"
+ "strings"
+)
+
+//go:generate stringer -linecomment -type=Version
+//go:generate stringer -linecomment -type=MetricCategory
+//go:generate stringer -linecomment -type=V2MetricKey
+//go:generate stringer -linecomment -type=V2Metric
+//go:generate stringer -linecomment -type=V3MetricKey
+//go:generate stringer -linecomment -type=V3Metric
+
+// CVSS version
+type Version byte
+
+const (
+ V20 Version = iota // 2.0
+ V30 // 3.0
+ V31 // 3.1
+)
+
+// CVSS metric category.
+type MetricCategory byte
+
+const (
+ Base MetricCategory = iota // Base
+ Temporal // Temporal
+ Environmental // Environmental
+)
+
+// CVSS metric key
+type V2MetricKey byte
+
+const (
+ V2AccessVector V2MetricKey = iota // AV
+ V2AccessComplexity // AC
+ V2Authentication // Au
+ V2ConfidentialityImpact // C
+ V2IntegrityImpact // I
+ V2AvailabilityImpact // A
+ V2Exploitability // E
+ V2RemediationLevel // RL
+ V2ReportConfidence // RC
+ V2CollateralDamagePotential // CDP
+ V2TargetDistribution // TD
+ V2ConfidentialityRequirement // CR
+ V2IntegrityRequirement // IR
+ V2AvailabilityRequirement // AR
+)
+
+// CVSS V2 metric key info lut
+var v2MetricKeys = map[V2MetricKey]struct {
+ Name string
+ Category MetricCategory
+} {
+ V2AccessVector: { "Access Vector", Base },
+ V2AccessComplexity: { "Access Complexity", Base },
+ V2Authentication: { "Authentication", Base },
+ V2ConfidentialityImpact: { "Confidentiality Impact", Base },
+ V2IntegrityImpact: { "Integrity Impact", Base },
+ V2AvailabilityImpact: { "Availability Impact", Base },
+ V2Exploitability: { "Exploitability", Temporal },
+ V2RemediationLevel: { "Remediation Level", Temporal },
+ V2ReportConfidence: { "Report Confidence", Temporal },
+ V2CollateralDamagePotential: { "Collateral Damage Potential", Environmental },
+ V2TargetDistribution: { "Target Distribution", Environmental },
+ V2ConfidentialityRequirement: { "Confidentiality Requirement", Environmental },
+ V2IntegrityRequirement: { "Integrity Requirement", Environmental },
+ V2AvailabilityRequirement: { "Availability Requirement", Environmental },
+}
+
+// v2 metric key IDs lut
+var v2MetricKeyIds = map[string]V2MetricKey {
+ "AV": V2AccessVector,
+ "AC": V2AccessComplexity,
+ "Au": V2Authentication,
+ "C": V2ConfidentialityImpact,
+ "I": V2IntegrityImpact,
+ "A": V2AvailabilityImpact,
+ "E": V2Exploitability,
+ "RL": V2RemediationLevel,
+ "RC": V2ReportConfidence,
+ "CDP": V2CollateralDamagePotential,
+ "TD": V2TargetDistribution,
+ "CR": V2ConfidentialityRequirement,
+ "IR": V2IntegrityRequirement,
+ "AR": V2AvailabilityRequirement,
+}
+
+// Get metric key from string.
+func GetV2MetricKeyFromString(s string) (V2MetricKey, error) {
+ k, ok := v2MetricKeyIds[s]
+ if ok {
+ return k, nil
+ } else {
+ return V2AccessVector, fmt.Errorf("unknown metric key: %s", s)
+ }
+}
+
+// Get metric key name.
+func (k V2MetricKey) Name() string {
+ return v2MetricKeys[k].Name
+}
+
+// Get metric key category.
+func (k V2MetricKey) Category() MetricCategory {
+ return v2MetricKeys[k].Category
+}
+
+// CVSS v2 metric value
+type V2Metric byte
+
+const (
+ V2AVNetwork V2Metric = iota // AV:N
+ V2AVAdjacentNetwork // AV:A
+ V2AVLocal // AV:L
+
+ V2ACLow // AC:L
+ V2ACMedium // AC:L
+ V2ACHigh // AC:H
+
+ V2AuMultiple // Au:M
+ V2AuSingle // Au:S
+ V2AuNone // Au:N
+
+ V2CNone // C:N
+ V2CPartial // C:P
+ V2CComplete // C:C
+
+ V2INone // I:N
+ V2IPartial // I:P
+ V2IComplete // I:C
+
+ V2ANone // A:N
+ V2APartial // A:P
+ V2AComplete // A:C
+
+ V2ENotDefined // E:ND
+ V2EUnproven // E:U
+ V2EProofOfConcept // E:POC
+ V2EFunctional // E:F
+ V2EHigh // E:H
+
+ V2RLOfficialFix // RL:OF
+ V2RLTemporaryFix // RL:TF
+ V2RLWorkaround // RL:W
+ V2RLUnavailable // RL:U
+ V2RLNotDefined // RL:ND
+
+ V2RCUnconfirmed // RC:UC
+ V2RCUncorroborated // RC:UR
+ V2RCConfirmed // RC:C
+ V2RCNotDefined // RC:ND
+
+ V2CDPNone // CDP:N
+ V2CDPLow // CDP:L
+ V2CDPLowMedium // CDP:LM
+ V2CDPMediumHigh // CDP:MH
+ V2CDPHigh // CDP:H
+ V2CDPNotDefined // CDP:ND
+
+ V2TDNone // TD:N
+ V2TDLow // TD:L
+ V2TDMedium // TD:M
+ V2TDHigh // TD:H
+ V2TDNotDefined // TD:ND
+
+ V2CRLow // CR:L
+ V2CRMedium // CR:M
+ V2CRHigh // CR:H
+ V2CRNotDefined // CR:ND
+
+ V2IRLow // IR:L
+ V2IRMedium // IR:M
+ V2IRHigh // IR:H
+ V2IRNotDefined // IR:ND
+
+ V2ARLow // AR:L
+ V2ARMedium // AR:M
+ V2ARHigh // AR:H
+ V2ARNotDefined // AR:ND
+)
+
+// map of metrics to metric keys
+var v2MetricKeyLut = map[V2Metric]V2MetricKey {
+ V2AVNetwork: V2AccessVector,
+ V2AVAdjacentNetwork: V2AccessVector,
+ V2AVLocal: V2AccessVector,
+
+ V2ACLow: V2AccessComplexity,
+ V2ACMedium: V2AccessComplexity,
+ V2ACHigh: V2AccessComplexity,
+
+ V2AuMultiple: V2Authentication,
+ V2AuSingle: V2Authentication,
+ V2AuNone: V2Authentication,
+
+ V2CNone: V2ConfidentialityImpact,
+ V2CPartial: V2ConfidentialityImpact,
+ V2CComplete: V2ConfidentialityImpact,
+
+ V2INone: V2IntegrityImpact,
+ V2IPartial: V2IntegrityImpact,
+ V2IComplete: V2IntegrityImpact,
+
+ V2ANone: V2AvailabilityImpact,
+ V2APartial: V2AvailabilityImpact,
+ V2AComplete: V2AvailabilityImpact,
+
+ V2ENotDefined: V2Exploitability,
+ V2EUnproven: V2Exploitability,
+ V2EProofOfConcept: V2Exploitability,
+ V2EFunctional: V2Exploitability,
+ V2EHigh: V2Exploitability,
+
+ V2RLOfficialFix: V2RemediationLevel,
+ V2RLTemporaryFix: V2RemediationLevel,
+ V2RLWorkaround: V2RemediationLevel,
+ V2RLUnavailable: V2RemediationLevel,
+ V2RLNotDefined: V2RemediationLevel,
+
+ V2RCUnconfirmed: V2ReportConfidence,
+ V2RCUncorroborated: V2ReportConfidence,
+ V2RCConfirmed: V2ReportConfidence,
+ V2RCNotDefined: V2ReportConfidence,
+
+ V2CDPNone: V2CollateralDamagePotential,
+ V2CDPLow: V2CollateralDamagePotential,
+ V2CDPLowMedium: V2CollateralDamagePotential,
+ V2CDPMediumHigh: V2CollateralDamagePotential,
+ V2CDPHigh: V2CollateralDamagePotential,
+ V2CDPNotDefined: V2CollateralDamagePotential,
+
+ V2TDNone: V2TargetDistribution,
+ V2TDLow: V2TargetDistribution,
+ V2TDMedium: V2TargetDistribution,
+ V2TDHigh: V2TargetDistribution,
+ V2TDNotDefined: V2TargetDistribution,
+
+ V2CRLow: V2ConfidentialityRequirement,
+ V2CRMedium: V2ConfidentialityRequirement,
+ V2CRHigh: V2ConfidentialityRequirement,
+ V2CRNotDefined: V2ConfidentialityRequirement,
+
+ V2IRLow: V2IntegrityRequirement,
+ V2IRMedium: V2IntegrityRequirement,
+ V2IRHigh: V2IntegrityRequirement,
+ V2IRNotDefined: V2IntegrityRequirement,
+
+ V2ARLow: V2AvailabilityRequirement,
+ V2ARMedium: V2AvailabilityRequirement,
+ V2ARHigh: V2AvailabilityRequirement,
+ V2ARNotDefined: V2AvailabilityRequirement,
+}
+
+// map of metric strings to metrics
+var v2MetricStrLut = map[string]V2Metric {
+ "AV:N": V2AVNetwork,
+ "AV:A": V2AVAdjacentNetwork,
+ "AV:L": V2AVLocal,
+
+ "AC:L": V2ACLow,
+ "AC:M": V2ACMedium,
+ "AC:H": V2ACHigh,
+
+ "Au:M": V2AuMultiple,
+ "Au:S": V2AuSingle,
+ "Au:N": V2AuNone,
+
+ "C:N": V2CNone,
+ "C:P": V2CPartial,
+ "C:C": V2CComplete,
+
+ "I:N": V2INone,
+ "I:P": V2IPartial,
+ "I:C": V2IComplete,
+
+ "A:N": V2ANone,
+ "A:P": V2APartial,
+ "A:C": V2AComplete,
+
+ "E:ND": V2ENotDefined,
+ "E:U": V2EUnproven,
+ "E:POC": V2EProofOfConcept,
+ "E:F": V2EFunctional,
+ "E:H": V2EHigh,
+
+ "RL:OF": V2RLOfficialFix,
+ "RL:TF": V2RLTemporaryFix,
+ "RL:W": V2RLWorkaround,
+ "RL:U": V2RLUnavailable,
+ "RL:ND": V2RLNotDefined,
+
+ "RC:UC": V2RCUnconfirmed,
+ "RC:UR": V2RCUncorroborated,
+ "RC:C": V2RCConfirmed,
+ "RC:ND": V2RCNotDefined,
+
+ "CDP:N": V2CDPNone,
+ "CDP:L": V2CDPLow,
+ "CDP:LM": V2CDPLowMedium,
+ "CDP:MH": V2CDPMediumHigh,
+ "CDP:H": V2CDPHigh,
+ "CDP:ND": V2CDPNotDefined,
+
+ "TD:N": V2TDNone,
+ "TD:L": V2TDLow,
+ "TD:M": V2TDMedium,
+ "TD:H": V2TDHigh,
+ "TD:ND": V2TDNotDefined,
+
+ "CR:L": V2CRLow,
+ "CR:M": V2CRMedium,
+ "CR:H": V2CRHigh,
+ "CR:ND": V2CRNotDefined,
+
+ "IR:L": V2IRLow,
+ "IR:M": V2IRMedium,
+ "IR:H": V2IRHigh,
+ "IR:ND": V2IRNotDefined,
+
+ "AR:L": V2ARLow,
+ "AR:M": V2ARMedium,
+ "AR:H": V2ARHigh,
+ "AR:ND": V2ARNotDefined,
+}
+
+// Convert string to CVSS 2.0 metric.
+func GetV2MetricFromString(s string) (V2Metric, error) {
+ // get metric
+ m, ok := v2MetricStrLut[s]
+ if !ok {
+ return V2AVNetwork, fmt.Errorf("invalid metric: %s", s)
+ }
+
+ // return success
+ return m, nil
+}
+
+// CVSS 2.0 vector.
+type v2Vector []V2Metric
+
+// Convert vector to string
+func (v v2Vector) String() string {
+ // convert to slice of metrics
+ metrics := []V2Metric(v)
+
+ // build vector
+ r := make([]string, len(metrics))
+ for i, m := range(metrics) {
+ r[i] = m.String()
+ }
+
+ // build and return string
+ return strings.Join(r, "/")
+}
+
+// Return CVSS version.
+func (v2Vector) Version() Version {
+ return V20
+}
+
+// create CVSS 2.0 vector from string
+func NewV2VectorFromString(s string) (Vector, error) {
+ strs := strings.Split(s, "/")
+ r := make([]V2Metric, len(strs))
+
+ // walk metric strings
+ for i, ms := range(strs) {
+ // convert string to vector
+ m, err := GetV2MetricFromString(ms)
+ if err != nil {
+ return nil, err
+ }
+
+ // add to results
+ r[i] = m
+ }
+
+ // build and return vector
+ return v2Vector(r), nil
+}
+
+// CVSS v3 metric key
+type V3MetricKey byte
+
+const (
+ V3AttackVector V3MetricKey = iota // AV
+ V3AttackComplexity // AC
+ V3PrivilegesRequired // PR
+ V3UserInteraction // UI
+ V3Scope // S
+ V3Confidentiality // C
+ V3Integrity // I
+ V3Availability // A
+ V3ExploitCodeMaturity // E
+ V3RemediationLevel // RL
+ V3ReportConfidence // RC
+ V3ConfidentialityRequirement // CR
+ V3IntegrityRequirement // IR
+ V3AvailabilityRequirement // AR
+ V3ModifiedAttackVector // MAV
+ V3ModifiedAttackComplexity // MAC
+ V3ModifiedPrivilegesRequired // MPR
+ V3ModifiedUserInteraction // MUI
+ V3ModifiedScope // MS
+ V3ModifiedConfidentiality // MC
+ V3ModifiedIntegrity // MI
+ V3ModifiedAvailability // MA
+)
+
+// CVSS V3 metric key info lut
+var v3MetricKeys = map[V3MetricKey]struct {
+ Name string
+ Category MetricCategory
+} {
+ V3AttackVector: { "Attack Vector", Base },
+ V3AttackComplexity: { "Attack Complexity", Base },
+ V3PrivilegesRequired: { "Privileges Required", Base },
+ V3UserInteraction: { "User Interaction", Base },
+ V3Scope: { "Scope", Base },
+ V3Confidentiality: { "Confidentiality", Base },
+ V3Integrity: { "Integrity", Base },
+ V3Availability: { "Availability", Base },
+ V3ExploitCodeMaturity: { "Exploit Code Maturity", Temporal },
+ V3RemediationLevel: { "Remediation Level", Temporal },
+ V3ReportConfidence: { "Report Confidence", Temporal },
+ V3ConfidentialityRequirement: { "Confidentiality Requirement", Environmental },
+ V3IntegrityRequirement: { "Integrity Requirement", Environmental },
+ V3AvailabilityRequirement: { "Availability Requirement", Environmental },
+ V3ModifiedAttackVector: { "Modified Attack Vector", Environmental },
+ V3ModifiedAttackComplexity: { "Modified Attack Complexity", Environmental },
+ V3ModifiedPrivilegesRequired: { "Modified Privileges Required", Environmental },
+ V3ModifiedUserInteraction: { "Modified User Interaction", Environmental },
+ V3ModifiedScope: { "Modified Scope", Environmental },
+ V3ModifiedConfidentiality: { "Modified Confidentiality", Environmental },
+ V3ModifiedIntegrity: { "Modified Integrity", Environmental },
+ V3ModifiedAvailability: { "Modified Availability", Environmental },
+}
+
+// metric key IDs lut
+var v3MetricKeyIds = map[string]V3MetricKey {
+ "AV": V3AttackVector,
+ "AC": V3AttackComplexity,
+ "PR": V3PrivilegesRequired,
+ "UI": V3UserInteraction,
+ "S": V3Scope,
+ "C": V3Confidentiality,
+ "I": V3Integrity,
+ "A": V3Availability,
+ "E": V3ExploitCodeMaturity,
+ "RL": V3RemediationLevel,
+ "RC": V3ReportConfidence,
+ "CR": V3ConfidentialityRequirement,
+ "IR": V3IntegrityRequirement,
+ "AR": V3AvailabilityRequirement,
+ "MAV": V3ModifiedAttackVector,
+ "MAC": V3ModifiedAttackComplexity,
+ "MPR": V3ModifiedPrivilegesRequired,
+ "MUI": V3ModifiedUserInteraction,
+ "MS": V3ModifiedScope,
+ "MC": V3ModifiedConfidentiality,
+ "MI": V3ModifiedIntegrity,
+ "MA": V3ModifiedAvailability,
+}
+
+// Get metric key from string.
+func GetV3MetricKeyFromString(s string) (V3MetricKey, error) {
+ k, ok := v3MetricKeyIds[s]
+ if ok {
+ return k, nil
+ } else {
+ return V3AttackVector, fmt.Errorf("unknown metric key: %s", s)
+ }
+}
+
+// Get metric key name.
+func (k V3MetricKey) Name() string {
+ return v3MetricKeys[k].Name
+}
+
+// Get metric key category.
+func (k V3MetricKey) Category() MetricCategory {
+ return v3MetricKeys[k].Category
+}
+
+// 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
+
+ V3MMRNotDefined // MPR:X
+ V3MPRLow // MPR:L
+ V3MPRHigh // MPR:H
+
+ V3MUINotDefined // MUI:X
+ V3MUINone // MUI:N
+ V3MUIRequired // MUI:R
+
+ V3MSNotDefined // MMS:X
+ V3MSUnchanged // MMS:U
+ V3MSChanged // MMS: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
+ V3UnknownMetric // unknown
+)
+
+// map of metrics to metric keys
+var v3MetricKeyLut = map[V3Metric]V3MetricKey {
+ 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
+
+ V3MMRNotDefined: V3ModifiedPrivilegesRequired, // MPR:X
+ V3MPRLow: V3ModifiedPrivilegesRequired, // MPR:L
+ V3MPRHigh: V3ModifiedPrivilegesRequired, // MPR:H
+
+ V3MUINotDefined: V3ModifiedUserInteraction, // MUI:X
+ V3MUINone: V3ModifiedUserInteraction, // MUI:N
+ V3MUIRequired: V3ModifiedUserInteraction, // MUI:R
+
+ V3MSNotDefined: V3ModifiedScope, // MMS:X
+ V3MSUnchanged: V3ModifiedConfidentiality, // MMS:U
+ V3MSChanged: V3ModifiedIntegrity, // MMS: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": V3MMRNotDefined,
+ "MPR:L": V3MPRLow,
+ "MPR:H": V3MPRHigh,
+
+ "MUI:X": V3MUINotDefined,
+ "MUI:N": V3MUINone,
+ "MUI:R": V3MUIRequired,
+
+ "MMS:X": V3MSNotDefined,
+ "MMS:U": V3MSUnchanged,
+ "MMS: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,
+}
+
+// Convert string to CVSS 3.1 metric.
+func GetV3MetricFromString(s string) (V3Metric, error) {
+ // get metric
+ m, ok := v3MetricStrLut[s]
+ if !ok {
+ return V3AVNetwork, fmt.Errorf("invalid metric: %s", s)
+ }
+
+ // return success
+ return m, nil
+}
+
+// CVSS v3.0 prefix
+var v30Prefix = "CVSS:3.0/"
+
+// CVSS 3.0 vector.
+type v30Vector []V3Metric
+
+// Convert vector to string
+func (v v30Vector) String() string {
+ // convert to slice of metrics
+ metrics := []V3Metric(v)
+
+ // build vector
+ r := make([]string, len(metrics))
+ for i, m := range(metrics) {
+ r[i] = m.String()
+ }
+
+ // build and return string
+ return v30Prefix + strings.Join(r, "/")
+}
+
+// Return CVSS version.
+func (v30Vector) Version() Version {
+ return V30
+}
+
+// create CVSS 3.0 vector from string
+func NewV30VectorFromString(s string) (Vector, error) {
+ strs := strings.Split(s, "/")
+ r := make([]V3Metric, len(strs))
+
+ // walk metric strings
+ for i, ms := range(strs) {
+ // convert string to vector
+ m, err := GetV3MetricFromString(ms)
+ if err != nil {
+ return nil, err
+ }
+
+ // add to results
+ r[i] = m
+ }
+
+ // build and return vector
+ return v30Vector(r), nil
+}
+
+// CVSS v3.1 prefix
+var v31Prefix = "CVSS:3.1/"
+
+// CVSS 3.1 vector.
+type v31Vector []V3Metric
+
+// Convert vector to string
+func (v v31Vector) String() string {
+ // convert to slice of metrics
+ metrics := []V3Metric(v)
+
+ // build vector
+ r := make([]string, len(metrics))
+ for i, m := range(metrics) {
+ r[i] = m.String()
+ }
+
+ // build and return string
+ return v31Prefix + strings.Join(r, "/")
+}
+
+// Return CVSS version.
+func (v31Vector) Version() Version {
+ return V31
+}
+
+// create CVSS 3.1 vector from string
+func NewV31VectorFromString(s string) (Vector, error) {
+ strs := strings.Split(s, "/")
+ r := make([]V3Metric, len(strs))
+
+ // walk metric strings
+ for i, ms := range(strs) {
+ // convert string to vector
+ m, err := GetV3MetricFromString(ms)
+ if err != nil {
+ return nil, err
+ }
+
+ // add to results
+ r[i] = m
+ }
+
+ // build and return vector
+ return v31Vector(r), nil
+}
+
+// CVSS vector
+type Vector interface {
+ // Get CVSS version.
+ Version() Version
+
+ // Get CVSS vector string.
+ String() string
+}
+
+// Create new CVSS vector from vector string.
+func NewVector(s string) (Vector, error) {
+ if len(s) > len(v31Prefix) && s[:len(v31Prefix)] == v31Prefix {
+ // create CVSS v2.0 vector.
+ return NewV31VectorFromString(s[len(v31Prefix):])
+ } else if len(s) > len(v30Prefix) && s[:len(v30Prefix)] == v30Prefix {
+ // create CVSS v3.0 vector.
+ return NewV30VectorFromString(s[len(v30Prefix):])
+ } else {
+ // create CVSS V2 vector
+ return NewV2VectorFromString(s)
+ }
+}