Completed
Push — master ( ec4189...678e72 )
by kota
06:23
created

gost.RedHat.parseCwe   A

Complexity

Conditions 5

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
dl 0
loc 12
rs 9.3333
c 0
b 0
f 0
nop 1
1
/* Vuls - Vulnerability Scanner
2
Copyright (C) 2016  Future Architect, Inc. Japan.
3
4
This program is free software: you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation, either version 3 of the License, or
7
(at your option) any later version.
8
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
package gost
19
20
import (
21
	"encoding/json"
22
	"strconv"
23
	"strings"
24
25
	"github.com/future-architect/vuls/config"
26
	"github.com/future-architect/vuls/models"
27
	"github.com/future-architect/vuls/util"
28
	"github.com/knqyf263/gost/db"
29
	gostmodels "github.com/knqyf263/gost/models"
30
)
31
32
// RedHat is Gost client for RedHat family linux
33
type RedHat struct {
34
	Base
35
}
36
37
// FillWithGost fills cve information that has in Gost
38
func (red RedHat) FillWithGost(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
39
	if nCVEs, err = red.fillUnfixed(driver, r); err != nil {
40
		return 0, err
41
	}
42
	return nCVEs, red.fillFixed(driver, r)
43
}
44
45
func (red RedHat) fillFixed(driver db.DB, r *models.ScanResult) error {
46
	var cveIDs []string
47
	for cveID, vuln := range r.ScannedCves {
48
		if _, ok := vuln.CveContents[models.RedHatAPI]; ok {
49
			continue
50
		}
51
		cveIDs = append(cveIDs, cveID)
52
	}
53
54
	if red.isFetchViaHTTP() {
55
		prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
56
			"redhat", "cves")
57
		responses, err := getCvesViaHTTP(cveIDs, prefix)
58
		if err != nil {
59
			return err
60
		}
61
		for _, res := range responses {
62
			redCve := gostmodels.RedhatCVE{}
63
			if err := json.Unmarshal([]byte(res.json), &redCve); err != nil {
64
				return err
65
			}
66
			if redCve.ID == 0 {
67
				continue
68
			}
69
			cveCont := red.ConvertToModel(&redCve)
70
			v, _ := r.ScannedCves[res.request.cveID]
71
			v.CveContents[models.RedHatAPI] = *cveCont
72
			r.ScannedCves[res.request.cveID] = v
73
		}
74
	} else {
75
		if driver == nil {
76
			return nil
77
		}
78
		for cveID, redCve := range driver.GetRedhatMulti(cveIDs) {
79
			if redCve.ID == 0 {
80
				continue
81
			}
82
			cveCont := red.ConvertToModel(&redCve)
83
			v, _ := r.ScannedCves[cveID]
84
			v.CveContents[models.RedHatAPI] = *cveCont
85
			r.ScannedCves[cveID] = v
86
		}
87
	}
88
89
	return nil
90
}
91
92
func (red RedHat) fillUnfixed(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
93
	if red.isFetchViaHTTP() {
94
		prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
95
			"redhat", major(r.Release), "pkgs")
96
		responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
97
		if err != nil {
98
			return 0, err
99
		}
100
		for _, res := range responses {
101
			// CVE-ID: RedhatCVE
102
			cves := map[string]gostmodels.RedhatCVE{}
103
			if err := json.Unmarshal([]byte(res.json), &cves); err != nil {
104
				return 0, err
105
			}
106
107
			for _, cve := range cves {
108
				cveCont := red.ConvertToModel(&cve)
109
				v, ok := r.ScannedCves[cve.Name]
110
				if ok {
111
					if _, ok := v.CveContents[models.RedHatAPI]; ok {
112
						v.CveContents[models.RedHatAPI] = *cveCont
113
					} else {
114
						v = models.VulnInfo{
115
							CveID:       cveCont.CveID,
116
							CveContents: models.NewCveContents(*cveCont),
117
							Confidences: models.Confidences{models.RedHatAPIMatch},
118
						}
119
					}
120
				} else {
121
					v = models.VulnInfo{
122
						CveID:       cveCont.CveID,
123
						CveContents: models.NewCveContents(*cveCont),
124
						Confidences: models.Confidences{models.RedHatAPIMatch},
125
					}
126
					nCVEs++
127
				}
128
129
				pkgStats := red.mergePackageStates(v,
130
					cve.PackageState, r.Packages, r.Release)
131
				if 0 < len(pkgStats) {
132
					v.AffectedPackages = pkgStats
133
					r.ScannedCves[cve.Name] = v
134
				}
135
			}
136
		}
137
	} else {
138
		if driver == nil {
139
			return 0, nil
140
		}
141
		for _, pack := range r.Packages {
142
			// CVE-ID: RedhatCVE
143
			cves := map[string]gostmodels.RedhatCVE{}
144
			cves = driver.GetUnfixedCvesRedhat(major(r.Release), pack.Name)
145
			for _, cve := range cves {
146
				cveCont := red.ConvertToModel(&cve)
147
				v, ok := r.ScannedCves[cve.Name]
148
				if ok {
149
					if _, ok := v.CveContents[models.RedHatAPI]; ok {
150
						v.CveContents[models.RedHatAPI] = *cveCont
151
					} else {
152
						v = models.VulnInfo{
153
							CveID:       cveCont.CveID,
154
							CveContents: models.NewCveContents(*cveCont),
155
							Confidences: models.Confidences{models.RedHatAPIMatch},
156
						}
157
					}
158
				} else {
159
					v = models.VulnInfo{
160
						CveID:       cveCont.CveID,
161
						CveContents: models.NewCveContents(*cveCont),
162
						Confidences: models.Confidences{models.RedHatAPIMatch},
163
					}
164
					nCVEs++
165
				}
166
167
				pkgStats := red.mergePackageStates(v,
168
					cve.PackageState, r.Packages, r.Release)
169
				if 0 < len(pkgStats) {
170
					v.AffectedPackages = pkgStats
171
					r.ScannedCves[cve.Name] = v
172
				}
173
			}
174
		}
175
	}
176
	return nCVEs, nil
177
}
178
179
func (red RedHat) mergePackageStates(v models.VulnInfo, ps []gostmodels.RedhatPackageState, installed models.Packages, release string) (pkgStats models.PackageStatuses) {
180
	pkgStats = v.AffectedPackages
181
	for _, pstate := range ps {
182
		if pstate.Cpe !=
183
			"cpe:/o:redhat:enterprise_linux:"+major(release) {
184
			return
185
		}
186
187
		if !(pstate.FixState == "Will not fix" ||
188
			pstate.FixState == "Fix deferred") {
189
			return
190
		}
191
192
		if _, ok := installed[pstate.PackageName]; !ok {
193
			return
194
		}
195
196
		notFixedYet := false
197
		switch pstate.FixState {
198
		case "Will not fix", "Fix deferred":
199
			notFixedYet = true
200
		}
201
202
		pkgStats = pkgStats.Store(models.PackageStatus{
203
			Name:        pstate.PackageName,
204
			FixState:    pstate.FixState,
205
			NotFixedYet: notFixedYet,
206
		})
207
	}
208
	return
209
}
210
211
func (red RedHat) parseCwe(str string) (cwes []string) {
212
	if str != "" {
213
		s := strings.Replace(str, "(", "|", -1)
214
		s = strings.Replace(s, ")", "|", -1)
215
		s = strings.Replace(s, "->", "|", -1)
216
		for _, s := range strings.Split(s, "|") {
217
			if s != "" {
218
				cwes = append(cwes, s)
219
			}
220
		}
221
	}
222
	return
223
}
224
225
// ConvertToModel converts gost model to vuls model
226
func (red RedHat) ConvertToModel(cve *gostmodels.RedhatCVE) *models.CveContent {
227
	cwes := red.parseCwe(cve.Cwe)
228
229
	details := []string{}
230
	for _, detail := range cve.Details {
231
		details = append(details, detail.Detail)
232
	}
233
234
	v2score := 0.0
235
	if cve.Cvss.CvssBaseScore != "" {
236
		v2score, _ = strconv.ParseFloat(cve.Cvss.CvssBaseScore, 64)
237
	}
238
	v2severity := ""
239
	if v2score != 0 {
240
		v2severity = cve.ThreatSeverity
241
	}
242
243
	v3score := 0.0
244
	if cve.Cvss3.Cvss3BaseScore != "" {
245
		v3score, _ = strconv.ParseFloat(cve.Cvss3.Cvss3BaseScore, 64)
246
	}
247
	v3severity := ""
248
	if v3score != 0 {
249
		v3severity = cve.ThreatSeverity
250
	}
251
252
	var refs []models.Reference
253
	for _, r := range cve.References {
254
		refs = append(refs, models.Reference{Link: r.Reference})
255
	}
256
257
	return &models.CveContent{
258
		Type:          models.RedHatAPI,
259
		CveID:         cve.Name,
260
		Title:         cve.Bugzilla.Description,
261
		Summary:       strings.Join(details, "\n"),
262
		Cvss2Score:    v2score,
263
		Cvss2Vector:   cve.Cvss.CvssScoringVector,
264
		Cvss2Severity: v2severity,
265
		Cvss3Score:    v3score,
266
		Cvss3Vector:   cve.Cvss3.Cvss3ScoringVector,
267
		Cvss3Severity: v3severity,
268
		References:    refs,
269
		CweIDs:        cwes,
270
		Mitigation:    cve.Mitigation,
271
		Published:     cve.PublicDate,
272
		SourceLink:    "https://access.redhat.com/security/cve/" + cve.Name,
273
	}
274
}
275