diff --git a/ext/vulnmdsrc/nvd/json.go b/ext/vulnmdsrc/nvd/json.go index 306bfc27..03b549c5 100644 --- a/ext/vulnmdsrc/nvd/json.go +++ b/ext/vulnmdsrc/nvd/json.go @@ -41,6 +41,7 @@ type nvdCVEMetadata struct { type nvdImpact struct { BaseMetricV2 nvdBaseMetricV2 `json:"baseMetricV2"` + BaseMetricV3 nvdBaseMetricV3 `json:"baseMetricV3"` } type nvdBaseMetricV2 struct { @@ -57,6 +58,22 @@ type nvdCVSSv2 struct { AvailImpact string `json:"availabilityImpact"` } +type nvdBaseMetricV3 struct { + CVSSv3 nvdCVSSv3 `json:"cvssV3"` +} + +type nvdCVSSv3 struct { + Score float64 `json:"baseScore"` + AttackVector string `json:"attackVector"` + AttackComplexity string `json:"attackComplexity"` + PrivilegesRequired string `json:"privilegesRequired"` + UserInteraction string `json:"userInteraction"` + Scope string `json:"scope"` + ConfImpact string `json:"confidentialityImpact"` + IntegImpact string `json:"integrityImpact"` + AvailImpact string `json:"availabilityImpact"` +} + var vectorValuesToLetters map[string]string func init() { @@ -72,6 +89,12 @@ func init() { vectorValuesToLetters["MULTIPLE"] = "M" vectorValuesToLetters["PARTIAL"] = "P" vectorValuesToLetters["COMPLETE"] = "C" + + // CVSSv3 only + vectorValuesToLetters["PHYSICAL"] = "P" + vectorValuesToLetters["REQUIRED"] = "R" + vectorValuesToLetters["CHANGED"] = "C" + vectorValuesToLetters["UNCHANGED"] = "U" } func (n nvdEntry) Metadata() *NVDMetadata { @@ -81,6 +104,10 @@ func (n nvdEntry) Metadata() *NVDMetadata { Vectors: n.Impact.BaseMetricV2.CVSSv2.String(), Score: n.Impact.BaseMetricV2.CVSSv2.Score, }, + CVSSv3: NVDmetadataCVSSv3{ + Vectors: n.Impact.BaseMetricV3.CVSSv3.String(), + Score: n.Impact.BaseMetricV3.CVSSv3.Score, + }, } if metadata.CVSSv2.Vectors == "" { @@ -106,6 +133,24 @@ func (n nvdCVSSv2) String() string { return str } +func (n nvdCVSSv3) String() string { + var str string + addVec(&str, "AV", n.AttackVector) + addVec(&str, "AC", n.AttackComplexity) + addVec(&str, "PR", n.PrivilegesRequired) + addVec(&str, "UI", n.UserInteraction) + addVec(&str, "S", n.Scope) + addVec(&str, "C", n.ConfImpact) + addVec(&str, "I", n.IntegImpact) + addVec(&str, "A", n.AvailImpact) + str = strings.TrimSuffix(str, "/") + + if len(str) > 0 { + return fmt.Sprintf("CVSS:3.0/%s", str) + } + return str +} + func addVec(str *string, vec, val string) { if val != "" { if let, ok := vectorValuesToLetters[val]; ok { diff --git a/ext/vulnmdsrc/nvd/nvd.go b/ext/vulnmdsrc/nvd/nvd.go index 9ff44201..a4438a24 100644 --- a/ext/vulnmdsrc/nvd/nvd.go +++ b/ext/vulnmdsrc/nvd/nvd.go @@ -55,6 +55,7 @@ type appender struct { type NVDMetadata struct { CVSSv2 NVDmetadataCVSSv2 + CVSSv3 NVDmetadataCVSSv3 } type NVDmetadataCVSSv2 struct { @@ -63,6 +64,11 @@ type NVDmetadataCVSSv2 struct { Score float64 } +type NVDmetadataCVSSv3 struct { + Vectors string + Score float64 +} + func init() { vulnmdsrc.RegisterAppender(appenderName, &appender{}) } diff --git a/ext/vulnmdsrc/nvd/nvd_test.go b/ext/vulnmdsrc/nvd/nvd_test.go index 700b91dd..7bd24af9 100644 --- a/ext/vulnmdsrc/nvd/nvd_test.go +++ b/ext/vulnmdsrc/nvd/nvd_test.go @@ -68,6 +68,10 @@ func TestNVDParser(t *testing.T) { Vectors: "AV:N/AC:L/Au:N/C:P/I:P/A:P", Score: 7.5, }, + CVSSv3: NVDmetadataCVSSv3{ + Vectors: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + Score: 9.8, + }, } assert.Equal(t, wantMetadata, gotMetadata) }