1 /*
2 * This file is part of dependency-check-core.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Copyright (c) 2013 Jeremy Long. All Rights Reserved.
17 */
18 package org.owasp.dependencycheck.suppression;
19
20 import java.util.ArrayList;
21 import java.util.Iterator;
22 import java.util.List;
23 import org.apache.commons.lang3.StringUtils;
24 import org.owasp.dependencycheck.dependency.Dependency;
25 import org.owasp.dependencycheck.dependency.Identifier;
26 import org.owasp.dependencycheck.dependency.Vulnerability;
27
28 /**
29 *
30 * @author Jeremy Long
31 */
32 public class SuppressionRule {
33
34 /**
35 * The file path for the suppression.
36 */
37 private PropertyType filePath;
38
39 /**
40 * Get the value of filePath.
41 *
42 * @return the value of filePath
43 */
44 public PropertyType getFilePath() {
45 return filePath;
46 }
47
48 /**
49 * Set the value of filePath.
50 *
51 * @param filePath new value of filePath
52 */
53 public void setFilePath(PropertyType filePath) {
54 this.filePath = filePath;
55 }
56 /**
57 * The sha1 hash.
58 */
59 private String sha1;
60
61 /**
62 * Get the value of sha1.
63 *
64 * @return the value of sha1
65 */
66 public String getSha1() {
67 return sha1;
68 }
69
70 /**
71 * Set the value of sha1.
72 *
73 * @param sha1 new value of sha1
74 */
75 public void setSha1(String sha1) {
76 this.sha1 = sha1;
77 }
78 /**
79 * A list of CPEs to suppression
80 */
81 private List<PropertyType> cpe = new ArrayList<PropertyType>();
82
83 /**
84 * Get the value of cpe.
85 *
86 * @return the value of cpe
87 */
88 public List<PropertyType> getCpe() {
89 return cpe;
90 }
91
92 /**
93 * Set the value of cpe.
94 *
95 * @param cpe new value of cpe
96 */
97 public void setCpe(List<PropertyType> cpe) {
98 this.cpe = cpe;
99 }
100
101 /**
102 * Adds the cpe to the cpe list.
103 *
104 * @param cpe the cpe to add
105 */
106 public void addCpe(PropertyType cpe) {
107 this.cpe.add(cpe);
108 }
109
110 /**
111 * Returns whether or not this suppression rule as CPE entries.
112 *
113 * @return whether or not this suppression rule as CPE entries
114 */
115 public boolean hasCpe() {
116 return !cpe.isEmpty();
117 }
118 /**
119 * The list of cvssBelow scores.
120 */
121 private List<Float> cvssBelow = new ArrayList<Float>();
122
123 /**
124 * Get the value of cvssBelow.
125 *
126 * @return the value of cvssBelow
127 */
128 public List<Float> getCvssBelow() {
129 return cvssBelow;
130 }
131
132 /**
133 * Set the value of cvssBelow.
134 *
135 * @param cvssBelow new value of cvssBelow
136 */
137 public void setCvssBelow(List<Float> cvssBelow) {
138 this.cvssBelow = cvssBelow;
139 }
140
141 /**
142 * Adds the cvss to the cvssBelow list.
143 *
144 * @param cvss the cvss to add
145 */
146 public void addCvssBelow(Float cvss) {
147 this.cvssBelow.add(cvss);
148 }
149
150 /**
151 * Returns whether or not this suppression rule has cvss suppressions.
152 *
153 * @return whether or not this suppression rule has cvss suppressions
154 */
155 public boolean hasCvssBelow() {
156 return !cvssBelow.isEmpty();
157 }
158 /**
159 * The list of cwe entries to suppress.
160 */
161 private List<String> cwe = new ArrayList<String>();
162
163 /**
164 * Get the value of cwe.
165 *
166 * @return the value of cwe
167 */
168 public List<String> getCwe() {
169 return cwe;
170 }
171
172 /**
173 * Set the value of cwe.
174 *
175 * @param cwe new value of cwe
176 */
177 public void setCwe(List<String> cwe) {
178 this.cwe = cwe;
179 }
180
181 /**
182 * Adds the cwe to the cwe list.
183 *
184 * @param cwe the cwe to add
185 */
186 public void addCwe(String cwe) {
187 this.cwe.add(cwe);
188 }
189
190 /**
191 * Returns whether this suppression rule has CWE entries.
192 *
193 * @return whether this suppression rule has CWE entries
194 */
195 public boolean hasCwe() {
196 return !cwe.isEmpty();
197 }
198 /**
199 * The list of cve entries to suppress.
200 */
201 private List<String> cve = new ArrayList<String>();
202
203 /**
204 * Get the value of cve.
205 *
206 * @return the value of cve
207 */
208 public List<String> getCve() {
209 return cve;
210 }
211
212 /**
213 * Set the value of cve.
214 *
215 * @param cve new value of cve
216 */
217 public void setCve(List<String> cve) {
218 this.cve = cve;
219 }
220
221 /**
222 * Adds the cve to the cve list.
223 *
224 * @param cve the cve to add
225 */
226 public void addCve(String cve) {
227 this.cve.add(cve);
228 }
229
230 /**
231 * Returns whether this suppression rule has CVE entries.
232 *
233 * @return whether this suppression rule has CVE entries
234 */
235 public boolean hasCve() {
236 return !cve.isEmpty();
237 }
238 /**
239 * A Maven GAV to suppression.
240 */
241 private PropertyType gav = null;
242
243 /**
244 * Get the value of Maven GAV.
245 *
246 * @return the value of gav
247 */
248 public PropertyType getGav() {
249 return gav;
250 }
251
252 /**
253 * Set the value of Maven GAV.
254 *
255 * @param gav new value of Maven gav
256 */
257 public void setGav(PropertyType gav) {
258 this.gav = gav;
259 }
260
261 /**
262 * Returns whether or not this suppression rule as GAV entries.
263 *
264 * @return whether or not this suppression rule as GAV entries
265 */
266 public boolean hasGav() {
267 return gav != null;
268 }
269
270 /**
271 * A flag indicating whether or not the suppression rule is a core/base rule that should not be included in the
272 * resulting report in the "suppressed" section.
273 */
274 private boolean base;
275
276 /**
277 * Get the value of base.
278 *
279 * @return the value of base
280 */
281 public boolean isBase() {
282 return base;
283 }
284
285 /**
286 * Set the value of base.
287 *
288 * @param base new value of base
289 */
290 public void setBase(boolean base) {
291 this.base = base;
292 }
293
294 /**
295 * Processes a given dependency to determine if any CPE, CVE, CWE, or CVSS scores should be suppressed. If any
296 * should be, they are removed from the dependency.
297 *
298 * @param dependency a project dependency to analyze
299 */
300 public void process(Dependency dependency) {
301 if (filePath != null && !filePath.matches(dependency.getFilePath())) {
302 return;
303 }
304 if (sha1 != null && !sha1.equalsIgnoreCase(dependency.getSha1sum())) {
305 return;
306 }
307 if (gav != null) {
308 final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
309 boolean gavFound = false;
310 while (itr.hasNext()) {
311 final Identifier i = itr.next();
312 if (identifierMatches("maven", this.gav, i)) {
313 gavFound = true;
314 break;
315 }
316 }
317 if (!gavFound) {
318 return;
319 }
320 }
321
322 if (this.hasCpe()) {
323 final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
324 while (itr.hasNext()) {
325 final Identifier i = itr.next();
326 for (PropertyType c : this.cpe) {
327 if (identifierMatches("cpe", c, i)) {
328 if (!isBase()) {
329 dependency.addSuppressedIdentifier(i);
330 }
331 itr.remove();
332 break;
333 }
334 }
335 }
336 }
337 if (hasCve() || hasCwe() || hasCvssBelow()) {
338 final Iterator<Vulnerability> itr = dependency.getVulnerabilities().iterator();
339 while (itr.hasNext()) {
340 boolean remove = false;
341 final Vulnerability v = itr.next();
342 for (String entry : this.cve) {
343 if (entry.equalsIgnoreCase(v.getName())) {
344 remove = true;
345 break;
346 }
347 }
348 if (!remove) {
349 for (String entry : this.cwe) {
350 if (v.getCwe() != null) {
351 final String toMatch = String.format("CWE-%s ", entry);
352 final String toTest = v.getCwe().substring(0, toMatch.length()).toUpperCase();
353 if (toTest.equals(toMatch)) {
354 remove = true;
355 break;
356 }
357 }
358 }
359 }
360 if (!remove) {
361 for (float cvss : this.cvssBelow) {
362 if (v.getCvssScore() < cvss) {
363 remove = true;
364 break;
365 }
366 }
367 }
368 if (remove) {
369 if (!isBase()) {
370 dependency.addSuppressedVulnerability(v);
371 }
372 itr.remove();
373 }
374 }
375 }
376 }
377
378 /**
379 * Identifies if the cpe specified by the cpe suppression rule does not specify a version.
380 *
381 * @param c a suppression rule identifier
382 * @return true if the property type does not specify a version; otherwise false
383 */
384 boolean cpeHasNoVersion(PropertyType c) {
385 return !c.isRegex() && StringUtils.countMatches(c.getValue(), ':') == 3;
386 }
387
388 /**
389 * Determines if the cpeEntry specified as a PropertyType matches the given Identifier.
390 *
391 * @param identifierType the type of identifier ("cpe", "maven", etc.)
392 * @param suppressionEntry a suppression rule entry
393 * @param identifier a CPE identifier to check
394 * @return true if the entry matches; otherwise false
395 */
396 boolean identifierMatches(String identifierType, PropertyType suppressionEntry, Identifier identifier) {
397 if (identifierType.equals(identifier.getType())) {
398 if (suppressionEntry.matches(identifier.getValue())) {
399 return true;
400 } else if ("cpe".equals(identifierType) && cpeHasNoVersion(suppressionEntry)) {
401 if (suppressionEntry.isCaseSensitive()) {
402 return identifier.getValue().startsWith(suppressionEntry.getValue());
403 } else {
404 final String id = identifier.getValue().toLowerCase();
405 final String check = suppressionEntry.getValue().toLowerCase();
406 return id.startsWith(check);
407 }
408 }
409 }
410 return false;
411 }
412
413 /**
414 * Standard toString implementation.
415 *
416 * @return a string representation of this object
417 */
418 @Override
419 public String toString() {
420 final StringBuilder sb = new StringBuilder();
421 sb.append("SuppressionRule{");
422 if (filePath != null) {
423 sb.append("filePath=").append(filePath).append(',');
424 }
425 if (sha1 != null) {
426 sb.append("sha1=").append(sha1).append(',');
427 }
428 if (gav != null) {
429 sb.append("gav=").append(gav).append(',');
430 }
431 if (cpe != null && !cpe.isEmpty()) {
432 sb.append("cpe={");
433 for (PropertyType pt : cpe) {
434 sb.append(pt).append(',');
435 }
436 sb.append('}');
437 }
438 if (cwe != null && !cwe.isEmpty()) {
439 sb.append("cwe={");
440 for (String s : cwe) {
441 sb.append(s).append(',');
442 }
443 sb.append('}');
444 }
445 if (cve != null && !cve.isEmpty()) {
446 sb.append("cve={");
447 for (String s : cve) {
448 sb.append(s).append(',');
449 }
450 sb.append('}');
451 }
452 if (cvssBelow != null && !cvssBelow.isEmpty()) {
453 sb.append("cvssBelow={");
454 for (Float s : cvssBelow) {
455 sb.append(s).append(',');
456 }
457 sb.append('}');
458 }
459 sb.append('}');
460 return sb.toString();
461 }
462 }