package xml import ( "fmt" "strings" "time" ) // XML elements related to the 'vuln' namespace used to describe vulnerabilities and their remediations. // Vulnerability see // http://docs.oasis-open.org/csaf/csaf-cvrf/v1.2/cs01/csaf-cvrf-v1.2-cs01.html#_Toc493508834 // for more details. type Vulnerability struct { CVE string `xml:"CVE"` Score float64 `xml:"CVSSScoreSets>ScoreSet>BaseScore"` Revisions []RevisionHistory `xml:"RevisionHistory>Revision"` Remediations []VulnerabilityRemediation `xml:"Remediations>Remediation"` } type RevisionHistory struct { Date string `xml:"Date"` Description string `xml:"Description"` } // VulnerabilityRemediation See http://docs.oasis-open.org/csaf/csaf-cvrf/v1.2/cs01/csaf-cvrf-v1.2-cs01.html#_Toc493508854 // for more details. type VulnerabilityRemediation struct { Type string `xml:"Type,attr"` FixedBuild string `xml:"FixedBuild"` RestartRequired string `xml:"RestartRequired"` ProductIDs []string `xml:"ProductID"` Description string `xml:"Description"` URL string `xml:"URL"` Supercedence string `xml:"Supercedence"` } // IncludesVendorFix returns true if the vulnerability has a vendor fix targeting the product // identified by pID. func (v *Vulnerability) IncludesVendorFix(pID string) bool { for _, rem := range v.Remediations { if rem.IsVendorFix() { for _, vfPID := range rem.ProductIDs { if vfPID == pID { return true } } } } return false } // PublishedDateEpoch returns the date the vuln was published (if any) as an epoch func (v *Vulnerability) PublishedDateEpoch() *int64 { for _, rev := range v.Revisions { if strings.Index(rev.Description, "Information published") != -1 { dPublished, err := time.Parse("2006-01-02T15:04:05", rev.Date) if err != nil { return nil } epoch := dPublished.Unix() return &epoch } } return nil } func (rem *VulnerabilityRemediation) IsVendorFix() bool { return rem.Type == "Vendor Fix" && strings.HasPrefix(rem.URL, "https://catalog.update") && strings.HasSuffix(rem.URL, fmt.Sprintf("q=KB%s", rem.Description)) }