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