1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.xml.suppression;
19
20 import java.util.ArrayList;
21 import java.util.Calendar;
22 import java.util.List;
23 import java.util.Optional;
24 import javax.annotation.concurrent.NotThreadSafe;
25 import org.owasp.dependencycheck.exception.ParseException;
26 import org.owasp.dependencycheck.utils.DateUtil;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29 import org.xml.sax.Attributes;
30 import org.xml.sax.SAXException;
31 import org.xml.sax.helpers.DefaultHandler;
32
33
34
35
36
37
38
39 @NotThreadSafe
40 public class SuppressionHandler extends DefaultHandler {
41
42
43
44
45 private static final Logger LOGGER = LoggerFactory.getLogger(SuppressionHandler.class);
46
47
48
49
50 public static final String SUPPRESSION_GROUP = "suppressionGroup";
51
52
53
54 public static final String SUPPRESS = "suppress";
55
56
57
58 public static final String FILE_PATH = "filePath";
59
60
61
62 public static final String SHA1 = "sha1";
63
64
65
66 public static final String CVE = "cve";
67
68
69
70 public static final String VULNERABILITY_NAME = "vulnerabilityName";
71
72
73
74
75 public static final String NOTES = "notes";
76
77
78
79
80 public static final String CPE = "cpe";
81
82
83
84 public static final String CWE = "cwe";
85
86
87
88 public static final String GAV = "gav";
89
90
91
92 public static final String PACKAGE_URL = "packageUrl";
93
94
95
96 public static final String CVSS_BELOW = "cvssBelow";
97
98
99
100 public static final String CVSS_V2_BELOW = "cvssV2Below";
101
102
103
104 public static final String CVSS_V3_BELOW = "cvssV3Below";
105
106
107
108 public static final String CVSS_V4_BELOW = "cvssV4Below";
109
110
111
112 private final List<SuppressionRule> suppressionRules = new ArrayList<>();
113
114
115
116 private SuppressionRule rule;
117
118
119
120 private Attributes currentAttributes;
121
122
123
124 private StringBuilder currentText;
125
126 private Boolean groupBase = null;
127 private Calendar groupUntil = null;
128
129
130
131
132
133
134
135 public List<SuppressionRule> getSuppressionRules() {
136 return suppressionRules;
137 }
138
139
140
141
142
143
144
145
146
147
148 @Override
149 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
150 currentAttributes = attributes;
151 currentText = new StringBuilder();
152
153 if (SUPPRESSION_GROUP.equals(qName)) {
154 groupBase = attributes.getValue("base") != null ? Boolean.parseBoolean(attributes.getValue("base")) : null;
155 groupUntil = parseUntilAttribute(attributes).orElse(null);
156 }
157
158 if (SUPPRESS.equals(qName)) {
159 Boolean base = attributes.getValue("base") != null ? Boolean.parseBoolean(attributes.getValue("base")) : null;
160 Calendar until = parseUntilAttribute(attributes).orElse(null);
161
162 rule = new SuppressionRule();
163
164 rule.setBase(base != null ? base : groupBase);
165 rule.setUntil(until != null ? until : groupUntil);
166 }
167 }
168
169
170
171
172
173
174
175
176 private static Optional<Calendar> parseUntilAttribute(Attributes attributes) throws SAXException {
177 String untilStr = attributes.getValue("until");
178 if (untilStr != null) {
179 try {
180 return Optional.of(DateUtil.parseXmlDate(untilStr));
181 } catch (ParseException ex) {
182 throw new SAXException("Unable to parse attribute 'until': " + untilStr, ex);
183 }
184 } else {
185 return Optional.empty();
186 }
187 }
188
189
190
191
192
193
194
195
196
197 @Override
198 public void endElement(String uri, String localName, String qName) throws SAXException {
199 if (null != qName) {
200 switch (qName) {
201 case SUPPRESS:
202 if (rule.getUntil() != null && rule.getUntil().before(Calendar.getInstance())) {
203 LOGGER.info("Suppression is expired for rule: {}", rule);
204 } else {
205 suppressionRules.add(rule);
206 }
207 rule = null;
208 break;
209 case SUPPRESSION_GROUP:
210 groupBase = null;
211 groupUntil = null;
212 break;
213 case FILE_PATH:
214 rule.setFilePath(processPropertyType());
215 break;
216 case SHA1:
217 rule.setSha1(currentText.toString().trim());
218 break;
219 case GAV:
220 rule.setGav(processPropertyType());
221 break;
222 case PACKAGE_URL:
223 rule.setPackageUrl(processPropertyType());
224 break;
225 case CPE:
226 rule.addCpe(processPropertyType());
227 break;
228 case CWE:
229 rule.addCwe(currentText.toString().trim());
230 break;
231 case CVE:
232 rule.addCve(currentText.toString().trim());
233 break;
234 case VULNERABILITY_NAME:
235 rule.addVulnerabilityName(processPropertyType());
236 break;
237 case NOTES:
238
239 if(rule != null) {
240 rule.setNotes(currentText.toString().trim());
241 }
242 break;
243 case CVSS_BELOW:
244 final Double cvss = Double.valueOf(currentText.toString().trim());
245 rule.addCvssBelow(cvss);
246 break;
247 case CVSS_V2_BELOW:
248 final Double cvssV2 = Double.valueOf(currentText.toString().trim());
249 rule.addCvssV2Below(cvssV2);
250 break;
251 case CVSS_V3_BELOW:
252 final Double cvssV3 = Double.valueOf(currentText.toString().trim());
253 rule.addCvssV3Below(cvssV3);
254 break;
255 case CVSS_V4_BELOW:
256 final Double cvssV4 = Double.valueOf(currentText.toString().trim());
257 rule.addCvssV4Below(cvssV4);
258 break;
259 default:
260 break;
261 }
262 }
263 }
264
265
266
267
268
269
270
271
272
273 @Override
274 public void characters(char[] ch, int start, int length) throws SAXException {
275 currentText.append(ch, start, length);
276 }
277
278
279
280
281
282
283
284 private PropertyType processPropertyType() {
285 final PropertyType pt = new PropertyType();
286 pt.setValue(currentText.toString().trim());
287 if (currentAttributes != null && currentAttributes.getLength() > 0) {
288 final String regex = currentAttributes.getValue("regex");
289 if (regex != null) {
290 pt.setRegex(Boolean.parseBoolean(regex));
291 }
292 final String caseSensitive = currentAttributes.getValue("caseSensitive");
293 if (caseSensitive != null) {
294 pt.setCaseSensitive(Boolean.parseBoolean(caseSensitive));
295 }
296 }
297 return pt;
298 }
299 }