gost/redhat.go   B
last analyzed

Size/Duplication

Total Lines 270
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 50
eloc 188
dl 0
loc 270
rs 8.4
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A gost.RedHat.FillWithGost 0 5 2
B gost.RedHat.mergePackageStates 0 30 7
F gost.RedHat.fillFixed 0 69 15
F gost.RedHat.fillUnfixed 0 76 15
A gost.RedHat.parseCwe 0 12 4
B gost.RedHat.ConvertToModel 0 47 7
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 config.Conf.Gost.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, ok := r.ScannedCves[res.request.cveID]
71
			if ok {
72
				if v.CveContents == nil {
73
					v.CveContents = models.NewCveContents(*cveCont)
74
				} else {
75
					v.CveContents[models.RedHatAPI] = *cveCont
76
				}
77
			} else {
78
				v = models.VulnInfo{
79
					CveID:       cveCont.CveID,
80
					CveContents: models.NewCveContents(*cveCont),
81
					Confidences: models.Confidences{models.RedHatAPIMatch},
82
				}
83
			}
84
			r.ScannedCves[res.request.cveID] = v
85
		}
86
	} else {
87
		if driver == nil {
88
			return nil
89
		}
90
		for cveID, redCve := range driver.GetRedhatMulti(cveIDs) {
91
			if redCve.ID == 0 {
92
				continue
93
			}
94
			cveCont := red.ConvertToModel(&redCve)
95
			v, ok := r.ScannedCves[cveID]
96
			if ok {
97
				if v.CveContents == nil {
98
					v.CveContents = models.NewCveContents(*cveCont)
99
				} else {
100
					v.CveContents[models.RedHatAPI] = *cveCont
101
				}
102
			} else {
103
				v = models.VulnInfo{
104
					CveID:       cveCont.CveID,
105
					CveContents: models.NewCveContents(*cveCont),
106
					Confidences: models.Confidences{models.RedHatAPIMatch},
107
				}
108
			}
109
			r.ScannedCves[cveID] = v
110
		}
111
	}
112
113
	return nil
114
}
115
116
func (red RedHat) fillUnfixed(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
117
	if config.Conf.Gost.IsFetchViaHTTP() {
118
		prefix, _ := util.URLPathJoin(config.Conf.Gost.URL,
119
			"redhat", major(r.Release), "pkgs")
120
		responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
121
		if err != nil {
122
			return 0, err
123
		}
124
		for _, res := range responses {
125
			// CVE-ID: RedhatCVE
126
			cves := map[string]gostmodels.RedhatCVE{}
127
			if err := json.Unmarshal([]byte(res.json), &cves); err != nil {
128
				return 0, err
129
			}
130
131
			for _, cve := range cves {
132
				cveCont := red.ConvertToModel(&cve)
133
				v, ok := r.ScannedCves[cve.Name]
134
				if ok {
135
					if v.CveContents == nil {
136
						v.CveContents = models.NewCveContents(*cveCont)
137
					} else {
138
						v.CveContents[models.RedHatAPI] = *cveCont
139
					}
140
				} else {
141
					v = models.VulnInfo{
142
						CveID:       cveCont.CveID,
143
						CveContents: models.NewCveContents(*cveCont),
144
						Confidences: models.Confidences{models.RedHatAPIMatch},
145
					}
146
					nCVEs++
147
				}
148
				pkgStats := red.mergePackageStates(v,
149
					cve.PackageState, r.Packages, r.Release)
150
				if 0 < len(pkgStats) {
151
					v.AffectedPackages = pkgStats
152
					r.ScannedCves[cve.Name] = v
153
				}
154
			}
155
		}
156
	} else {
157
		if driver == nil {
158
			return 0, nil
159
		}
160
		for _, pack := range r.Packages {
161
			// CVE-ID: RedhatCVE
162
			cves := map[string]gostmodels.RedhatCVE{}
163
			cves = driver.GetUnfixedCvesRedhat(major(r.Release), pack.Name)
164
			for _, cve := range cves {
165
				cveCont := red.ConvertToModel(&cve)
166
				v, ok := r.ScannedCves[cve.Name]
167
				if ok {
168
					if v.CveContents == nil {
169
						v.CveContents = models.NewCveContents(*cveCont)
170
					} else {
171
						v.CveContents[models.RedHatAPI] = *cveCont
172
					}
173
				} else {
174
					v = models.VulnInfo{
175
						CveID:       cveCont.CveID,
176
						CveContents: models.NewCveContents(*cveCont),
177
						Confidences: models.Confidences{models.RedHatAPIMatch},
178
					}
179
					nCVEs++
180
				}
181
182
				pkgStats := red.mergePackageStates(v,
183
					cve.PackageState, r.Packages, r.Release)
184
				if 0 < len(pkgStats) {
185
					v.AffectedPackages = pkgStats
186
					r.ScannedCves[cve.Name] = v
187
				}
188
			}
189
		}
190
	}
191
	return nCVEs, nil
192
}
193
194
func (red RedHat) mergePackageStates(v models.VulnInfo, ps []gostmodels.RedhatPackageState, installed models.Packages, release string) (pkgStats models.PackageFixStatuses) {
195
	pkgStats = v.AffectedPackages
196
	for _, pstate := range ps {
197
		if pstate.Cpe !=
198
			"cpe:/o:redhat:enterprise_linux:"+major(release) {
199
			return
200
		}
201
202
		if !(pstate.FixState == "Will not fix" ||
203
			pstate.FixState == "Fix deferred") {
204
			return
205
		}
206
207
		if _, ok := installed[pstate.PackageName]; !ok {
208
			return
209
		}
210
211
		notFixedYet := false
212
		switch pstate.FixState {
213
		case "Will not fix", "Fix deferred":
214
			notFixedYet = true
215
		}
216
217
		pkgStats = pkgStats.Store(models.PackageFixStatus{
218
			Name:        pstate.PackageName,
219
			FixState:    pstate.FixState,
220
			NotFixedYet: notFixedYet,
221
		})
222
	}
223
	return
224
}
225
226
func (red RedHat) parseCwe(str string) (cwes []string) {
227
	if str != "" {
228
		s := strings.Replace(str, "(", "|", -1)
229
		s = strings.Replace(s, ")", "|", -1)
230
		s = strings.Replace(s, "->", "|", -1)
231
		for _, s := range strings.Split(s, "|") {
232
			if s != "" {
233
				cwes = append(cwes, s)
234
			}
235
		}
236
	}
237
	return
238
}
239
240
// ConvertToModel converts gost model to vuls model
241
func (red RedHat) ConvertToModel(cve *gostmodels.RedhatCVE) *models.CveContent {
242
	cwes := red.parseCwe(cve.Cwe)
243
244
	details := []string{}
245
	for _, detail := range cve.Details {
246
		details = append(details, detail.Detail)
247
	}
248
249
	v2score := 0.0
250
	if cve.Cvss.CvssBaseScore != "" {
251
		v2score, _ = strconv.ParseFloat(cve.Cvss.CvssBaseScore, 64)
252
	}
253
	v2severity := ""
254
	if v2score != 0 {
255
		v2severity = cve.ThreatSeverity
256
	}
257
258
	v3score := 0.0
259
	if cve.Cvss3.Cvss3BaseScore != "" {
260
		v3score, _ = strconv.ParseFloat(cve.Cvss3.Cvss3BaseScore, 64)
261
	}
262
	v3severity := ""
263
	if v3score != 0 {
264
		v3severity = cve.ThreatSeverity
265
	}
266
267
	var refs []models.Reference
268
	for _, r := range cve.References {
269
		refs = append(refs, models.Reference{Link: r.Reference})
270
	}
271
272
	return &models.CveContent{
273
		Type:          models.RedHatAPI,
274
		CveID:         cve.Name,
275
		Title:         cve.Bugzilla.Description,
276
		Summary:       strings.Join(details, "\n"),
277
		Cvss2Score:    v2score,
278
		Cvss2Vector:   cve.Cvss.CvssScoringVector,
279
		Cvss2Severity: v2severity,
280
		Cvss3Score:    v3score,
281
		Cvss3Vector:   cve.Cvss3.Cvss3ScoringVector,
282
		Cvss3Severity: v3severity,
283
		References:    refs,
284
		CweIDs:        cwes,
285
		Mitigation:    cve.Mitigation,
286
		Published:     cve.PublicDate,
287
		SourceLink:    "https://access.redhat.com/security/cve/" + cve.Name,
288
	}
289
}
290