mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 07:43:40 +01:00
added support for suppression rules, initial version
Former-commit-id: c58bea577282155661b4c6e1991178ea07e7eb98
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionParseException;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionParser;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* Abstract base suppression analyzer that contains methods for parsing the
|
||||
* suppression xml file.
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
/**
|
||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
||||
*
|
||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
||||
*/
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support.
|
||||
* @return whether or not the specified file extension is supported by this
|
||||
* analyzer.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsExtension(String extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//</editor-fold>
|
||||
/**
|
||||
* The initialize method loads the suppression XML file.
|
||||
*
|
||||
* @throws Exception thrown if there is an exception
|
||||
*/
|
||||
@Override
|
||||
public void initialize() throws Exception {
|
||||
super.initialize();
|
||||
loadSuppressionData();
|
||||
}
|
||||
/**
|
||||
* The list of suppression rules
|
||||
*/
|
||||
private List<SuppressionRule> rules;
|
||||
|
||||
/**
|
||||
* Get the value of rules.
|
||||
*
|
||||
* @return the value of rules
|
||||
*/
|
||||
public List<SuppressionRule> getRules() {
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of rules.
|
||||
*
|
||||
* @param rules new value of rules
|
||||
*/
|
||||
public void setRules(List<SuppressionRule> rules) {
|
||||
this.rules = rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the suppression rules file.
|
||||
*
|
||||
* @throws SuppressionParseException thrown if the XML cannot be parsed.
|
||||
*/
|
||||
private void loadSuppressionData() throws SuppressionParseException {
|
||||
final File file = Settings.getFile(Settings.KEYS.SUPPRESSION_FILE);
|
||||
if (file != null) {
|
||||
final SuppressionParser parser = new SuppressionParser();
|
||||
try {
|
||||
rules = parser.parseSuppressionRules(file);
|
||||
} catch (SuppressionParseException ex) {
|
||||
final String msg = String.format("Unable to parse suppression xml file '%s'", file.getPath());
|
||||
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING, ex.getMessage());
|
||||
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.FINE, null, ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
||||
|
||||
/**
|
||||
* The suppression analyzer processes an externally defined XML document that
|
||||
* complies with the suppressions.xsd schema. Any identified CPE entries within
|
||||
* the dependencies that match will be removed.
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Cpe Suppression Analyzer";
|
||||
/**
|
||||
* The phase that this analyzer is intended to run in.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_IDENTIFIER_ANALYSIS;
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase that the analyzer is intended to run in.
|
||||
*
|
||||
* @return the phase that the analyzer is intended to run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
@Override
|
||||
public void analyze(final Dependency dependency, final Engine engine) throws AnalysisException {
|
||||
|
||||
if (getRules() == null || getRules().size() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final SuppressionRule rule : getRules()) {
|
||||
rule.process(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
||||
|
||||
/**
|
||||
* The suppression analyzer processes an externally defined XML document that
|
||||
* complies with the suppressions.xsd schema. Any identified Vulnerability
|
||||
* entries within the dependencies that match will be removed.
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Vulnerability Suppression Analyzer";
|
||||
/**
|
||||
* The phase that this analyzer is intended to run in.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_FINDING_ANALYSIS;
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase that the analyzer is intended to run in.
|
||||
*
|
||||
* @return the phase that the analyzer is intended to run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
@Override
|
||||
public void analyze(final Dependency dependency, final Engine engine) throws AnalysisException {
|
||||
|
||||
if (getRules() == null || getRules().size() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final SuppressionRule rule : getRules()) {
|
||||
rule.process(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.suppression;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A simple PropertyType used to represent a string value that could be used as
|
||||
* a regular expression or could be case insensitive. The equals method has been
|
||||
* over-ridden so that the object will correctly compare to strings.
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class PropertyType {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="properties">
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Gets the value of the value property.
|
||||
*
|
||||
* @return the value of the value property
|
||||
*
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the value property.
|
||||
*
|
||||
* @param value the value of the value property
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
/**
|
||||
* Whether or not the expression is a regex.
|
||||
*/
|
||||
private boolean regex = false;
|
||||
|
||||
/**
|
||||
* Returns whether or not the value is a regex.
|
||||
*
|
||||
* @return true if the value is a regex, otherwise false
|
||||
*
|
||||
*/
|
||||
public boolean isRegex() {
|
||||
return regex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the value property is a regex.
|
||||
*
|
||||
* @param value true if the value is a regex, otherwise false
|
||||
*
|
||||
*/
|
||||
public void setRegex(boolean value) {
|
||||
this.regex = value;
|
||||
}
|
||||
/**
|
||||
* Indicates case sensitivity.
|
||||
*/
|
||||
protected boolean caseSensitive = false;
|
||||
|
||||
/**
|
||||
* Gets the value of the caseSensitive property.
|
||||
*
|
||||
* @return true if the value is case sensitive
|
||||
*
|
||||
*/
|
||||
public boolean isCaseSensitive() {
|
||||
return caseSensitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the caseSensitive property.
|
||||
*
|
||||
* @param value whether the value is case sensitive
|
||||
*
|
||||
*/
|
||||
public void setCaseSensitive(boolean value) {
|
||||
this.caseSensitive = value;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Uses the object's properties to determine if the supplied string matches
|
||||
* the value of this property.
|
||||
*
|
||||
* @param text the String to validate
|
||||
* @return whether the text supplied is matched by the value of the property
|
||||
*/
|
||||
public boolean matches(String text) {
|
||||
if (text == null) {
|
||||
return false;
|
||||
}
|
||||
if (this.regex) {
|
||||
Pattern rx;
|
||||
if (this.caseSensitive) {
|
||||
rx = Pattern.compile(this.value);
|
||||
} else {
|
||||
rx = Pattern.compile(this.value, Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
return rx.matcher(text).matches();
|
||||
} else {
|
||||
if (this.caseSensitive) {
|
||||
return value.equals(text);
|
||||
} else {
|
||||
return value.equalsIgnoreCase(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="standard implmentations of hashCode, equals, and toString">
|
||||
/**
|
||||
* Default implementation of hashCode.
|
||||
*
|
||||
* @return the hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
hash = 59 * hash + (this.value != null ? this.value.hashCode() : 0);
|
||||
hash = 59 * hash + (this.regex ? 1 : 0);
|
||||
hash = 59 * hash + (this.caseSensitive ? 1 : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation of equals.
|
||||
*
|
||||
* @param obj the object to compare
|
||||
* @return whether the objects are equivalent
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final PropertyType other = (PropertyType) obj;
|
||||
if ((this.value == null) ? (other.value != null) : !this.value.equals(other.value)) {
|
||||
return false;
|
||||
}
|
||||
if (this.regex != other.regex) {
|
||||
return false;
|
||||
}
|
||||
if (this.caseSensitive != other.caseSensitive) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation of toString().
|
||||
*
|
||||
* @return the string representation of the object
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PropertyType{" + "value=" + value + ", regex=" + regex + ", caseSensitive=" + caseSensitive + '}';
|
||||
}
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.owasp.dependencycheck.suppression;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
/**
|
||||
* An XML parsing error handler.
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class SuppressionErrorHandler implements ErrorHandler {
|
||||
|
||||
/**
|
||||
* Builds a prettier exception message.
|
||||
*
|
||||
* @param ex the SAXParseException
|
||||
* @return an easier to read exception message
|
||||
*/
|
||||
private String getPrettyParseExceptionInfo(SAXParseException ex) {
|
||||
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
|
||||
if (ex.getSystemId() != null) {
|
||||
sb.append("systemId=").append(ex.getSystemId()).append(", ");
|
||||
}
|
||||
if (ex.getPublicId() != null) {
|
||||
sb.append("publicId=").append(ex.getPublicId()).append(", ");
|
||||
}
|
||||
if (ex.getLineNumber() > 0) {
|
||||
sb.append("Line=").append(ex.getLineNumber());
|
||||
}
|
||||
if (ex.getColumnNumber() > 0) {
|
||||
sb.append(", Column=").append(ex.getColumnNumber());
|
||||
}
|
||||
sb.append(": ").append(ex.getMessage());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs warnings.
|
||||
*
|
||||
* @param ex the warning to log
|
||||
* @throws SAXException is never thrown
|
||||
*/
|
||||
@Override
|
||||
public void warning(SAXParseException ex) throws SAXException {
|
||||
Logger.getLogger(SuppressionErrorHandler.class.getName()).log(Level.FINE, null, ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles errors.
|
||||
*
|
||||
* @param ex the error to handle
|
||||
* @throws SAXException is always thrown
|
||||
*/
|
||||
@Override
|
||||
public void error(SAXParseException ex) throws SAXException {
|
||||
throw new SAXException(getPrettyParseExceptionInfo(ex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles fatal exceptions.
|
||||
*
|
||||
* @param ex a fatal exception
|
||||
* @throws SAXException is always
|
||||
*/
|
||||
@Override
|
||||
public void fatalError(SAXParseException ex) throws SAXException {
|
||||
throw new SAXException(getPrettyParseExceptionInfo(ex));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.suppression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* A handler to load suppression rules.
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class SuppressionHandler extends DefaultHandler {
|
||||
|
||||
/**
|
||||
* The suppress node, indicates the start of a new rule.
|
||||
*/
|
||||
public static final String SUPPRESS = "suppress";
|
||||
/**
|
||||
* The file path element name.
|
||||
*/
|
||||
public static final String FILE_PATH = "filePath";
|
||||
/**
|
||||
* The sha1 hash element name.
|
||||
*/
|
||||
public static final String SHA1 = "sha1";
|
||||
/**
|
||||
* The CVE element name.
|
||||
*/
|
||||
public static final String CVE = "cve";
|
||||
/**
|
||||
* The CPE element name.
|
||||
*/
|
||||
public static final String CPE = "cpe";
|
||||
/**
|
||||
* The CWE element name.
|
||||
*/
|
||||
public static final String CWE = "cwe";
|
||||
/**
|
||||
* The cvssBelow element name.
|
||||
*/
|
||||
public static final String CVSS_BELOW = "cvssBelow";
|
||||
/**
|
||||
* A list of suppression rules.
|
||||
*/
|
||||
private List<SuppressionRule> supressionRules = new ArrayList<SuppressionRule>();
|
||||
|
||||
/**
|
||||
* Get the value of supressionRules
|
||||
*
|
||||
* @return the value of supressionRules
|
||||
*/
|
||||
public List<SuppressionRule> getSupressionRules() {
|
||||
return supressionRules;
|
||||
}
|
||||
/**
|
||||
* The current rule being read.
|
||||
*/
|
||||
private SuppressionRule rule;
|
||||
/**
|
||||
* The attributes of the node being read.
|
||||
*/
|
||||
private Attributes currentAttributes;
|
||||
/**
|
||||
* The current node text being extracted from the element.
|
||||
*/
|
||||
private StringBuffer currentText;
|
||||
|
||||
/**
|
||||
* Handles the start element event.
|
||||
*
|
||||
* @param uri the uri of the element being processed
|
||||
* @param localName the local name of the element being processed
|
||||
* @param qName the qName of the element being processed
|
||||
* @param attributes the attributes of the element being processed
|
||||
* @throws SAXException thrown if there is an exception processing
|
||||
*/
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
currentAttributes = null;
|
||||
currentText = new StringBuffer();
|
||||
|
||||
if (SUPPRESS.equals(qName)) {
|
||||
rule = new SuppressionRule();
|
||||
} else if (FILE_PATH.equals(qName)) {
|
||||
currentAttributes = attributes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the end element event.
|
||||
*
|
||||
* @param uri the uri of the element
|
||||
* @param localName the local name of the element
|
||||
* @param qName the qName of the element
|
||||
* @throws SAXException thrown if there is an exception processing
|
||||
*/
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
if (SUPPRESS.equals(qName)) {
|
||||
supressionRules.add(rule);
|
||||
rule = null;
|
||||
} else if (FILE_PATH.equals(qName)) {
|
||||
PropertyType pt = processPropertyType();
|
||||
rule.setFilePath(pt);
|
||||
} else if (SHA1.equals(qName)) {
|
||||
rule.setSha1(currentText.toString());
|
||||
} else if (CPE.equals(qName)) {
|
||||
PropertyType pt = processPropertyType();
|
||||
rule.addCpe(pt);
|
||||
} else if (CWE.equals(qName)) {
|
||||
rule.addCwe(currentText.toString());
|
||||
} else if (CVE.equals(qName)) {
|
||||
rule.addCve(currentText.toString());
|
||||
} else if (CVSS_BELOW.equals(qName)) {
|
||||
float cvss = Float.parseFloat(currentText.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the body text of the node being processed.
|
||||
*
|
||||
* @param ch the char array of text
|
||||
* @param start the start position to copy text from in the char array
|
||||
* @param length the number of characters to copy from the char array
|
||||
* @throws SAXException thrown if there is a parsing exception
|
||||
*/
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length) throws SAXException {
|
||||
currentText.append(ch, start, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes field members that have been collected during the characters
|
||||
* and startElement method to construct a PropertyType object.
|
||||
*
|
||||
* @return a PropertyType object
|
||||
*/
|
||||
private PropertyType processPropertyType() {
|
||||
PropertyType pt = new PropertyType();
|
||||
pt.setValue(currentText.toString());
|
||||
if (currentAttributes != null && currentAttributes.getLength() > 0) {
|
||||
final String regex = currentAttributes.getValue("regex");
|
||||
if (regex != null) {
|
||||
pt.setRegex(Boolean.parseBoolean(regex));
|
||||
}
|
||||
final String caseSensitive = currentAttributes.getValue("caseSensitive");
|
||||
if (regex != null) {
|
||||
pt.setCaseSensitive(Boolean.parseBoolean(caseSensitive));
|
||||
}
|
||||
}
|
||||
return pt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.suppression;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
* A simple validating parser for XML Suppression Rules.
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class SuppressionParser {
|
||||
|
||||
/**
|
||||
* JAXP Schema Language, source:
|
||||
* http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
|
||||
*/
|
||||
public static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
|
||||
/**
|
||||
* W3C XML Schema, source:
|
||||
* http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
|
||||
*/
|
||||
public static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
|
||||
/**
|
||||
* JAXP Schema Source, source:
|
||||
* http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
|
||||
*/
|
||||
public static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
|
||||
|
||||
/**
|
||||
* Parses the given xml file and returns a list of the suppression rules
|
||||
* contained.
|
||||
*
|
||||
* @param file an xml file containing suppression rules
|
||||
* @return a list of suppression rules
|
||||
* @throws SuppressionParseException thrown if the xml file cannot be parsed
|
||||
*/
|
||||
public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
|
||||
try {
|
||||
File schema = new File(this.getClass().getClassLoader().getResource("schema/suppression.xsd").getPath());
|
||||
SuppressionHandler handler = new SuppressionHandler();
|
||||
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setValidating(true);
|
||||
SAXParser saxParser = factory.newSAXParser();
|
||||
saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_LANGUAGE, SuppressionParser.W3C_XML_SCHEMA);
|
||||
saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_SOURCE, schema);
|
||||
XMLReader xmlReader = saxParser.getXMLReader();
|
||||
xmlReader.setErrorHandler(new SuppressionErrorHandler());
|
||||
xmlReader.setContentHandler(handler);
|
||||
|
||||
InputStream inputStream = new FileInputStream(file);
|
||||
Reader reader = new InputStreamReader(inputStream); //, "UTF-8");
|
||||
InputSource in = new InputSource(reader);
|
||||
//in.setEncoding("UTF-8");
|
||||
|
||||
xmlReader.parse(in);
|
||||
|
||||
|
||||
return handler.getSupressionRules();
|
||||
} catch (ParserConfigurationException ex) {
|
||||
Logger.getLogger(SuppressionParser.class.getName()).log(Level.FINE, null, ex);
|
||||
throw new SuppressionParseException(ex);
|
||||
} catch (SAXException ex) {
|
||||
Logger.getLogger(SuppressionParser.class.getName()).log(Level.FINE, null, ex);
|
||||
throw new SuppressionParseException(ex);
|
||||
} catch (FileNotFoundException ex) {
|
||||
Logger.getLogger(SuppressionParser.class.getName()).log(Level.FINE, null, ex);
|
||||
throw new SuppressionParseException(ex);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(SuppressionParser.class.getName()).log(Level.FINE, null, ex);
|
||||
throw new SuppressionParseException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.suppression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class SuppressionRule {
|
||||
|
||||
/**
|
||||
* The file path for the suppression.
|
||||
*/
|
||||
private PropertyType filePath;
|
||||
|
||||
/**
|
||||
* Get the value of filePath.
|
||||
*
|
||||
* @return the value of filePath
|
||||
*/
|
||||
public PropertyType getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of filePath.
|
||||
*
|
||||
* @param filePath new value of filePath
|
||||
*/
|
||||
public void setFilePath(PropertyType filePath) {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
/**
|
||||
* The sha1 hash.
|
||||
*/
|
||||
private String sha1;
|
||||
|
||||
/**
|
||||
* Get the value of sha1.
|
||||
*
|
||||
* @return the value of sha1
|
||||
*/
|
||||
public String getSha1() {
|
||||
return sha1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of sha1.
|
||||
*
|
||||
* @param sha1 new value of sha1
|
||||
*/
|
||||
public void setSha1(String sha1) {
|
||||
this.sha1 = sha1;
|
||||
}
|
||||
/**
|
||||
* A list of CPEs to suppression
|
||||
*/
|
||||
private List<PropertyType> cpe = new ArrayList<PropertyType>();
|
||||
|
||||
/**
|
||||
* Get the value of cpe.
|
||||
*
|
||||
* @return the value of cpe
|
||||
*/
|
||||
public List<PropertyType> getCpe() {
|
||||
return cpe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cpe.
|
||||
*
|
||||
* @param cpe new value of cpe
|
||||
*/
|
||||
public void setCpe(List<PropertyType> cpe) {
|
||||
this.cpe = cpe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the cpe to the cpe list.
|
||||
*
|
||||
* @param cpe the cpe to add
|
||||
*/
|
||||
public void addCpe(PropertyType cpe) {
|
||||
this.cpe.add(cpe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this suppression rule as CPE entries.
|
||||
*
|
||||
* @return whether or not this suppression rule as CPE entries
|
||||
*/
|
||||
public boolean hasCpe() {
|
||||
return cpe.size() > 0;
|
||||
}
|
||||
/**
|
||||
* The list of cvssBelow scores.
|
||||
*/
|
||||
private List<Float> cvssBelow = new ArrayList<Float>();
|
||||
|
||||
/**
|
||||
* Get the value of cvssBelow
|
||||
*
|
||||
* @return the value of cvssBelow
|
||||
*/
|
||||
public List<Float> getCvssBelow() {
|
||||
return cvssBelow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cvssBelow
|
||||
*
|
||||
* @param cvssBelow new value of cvssBelow
|
||||
*/
|
||||
public void setCvssBelow(List<Float> cvssBelow) {
|
||||
this.cvssBelow = cvssBelow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the cvss to the cvssBelow list.
|
||||
*
|
||||
* @param cvss the cvss to add
|
||||
*/
|
||||
public void addCvssBelow(Float cvss) {
|
||||
this.cvssBelow.add(cvss);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this suppression rule has cvss suppressions.
|
||||
*
|
||||
* @return whether or not this suppression rule has cvss suppressions
|
||||
*/
|
||||
public boolean hasCvssBelow() {
|
||||
return cvssBelow.size() > 0;
|
||||
}
|
||||
/**
|
||||
* The list of cwe entries to suppress.
|
||||
*/
|
||||
private List<String> cwe = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Get the value of cwe.
|
||||
*
|
||||
* @return the value of cwe
|
||||
*/
|
||||
public List<String> getCwe() {
|
||||
return cwe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cwe.
|
||||
*
|
||||
* @param cwe new value of cwe
|
||||
*/
|
||||
public void setCwe(List<String> cwe) {
|
||||
this.cwe = cwe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the cwe to the cwe list.
|
||||
*
|
||||
* @param cwe the cwe to add
|
||||
*/
|
||||
public void addCwe(String cwe) {
|
||||
this.cwe.add(cwe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this suppression rule has CWE entries.
|
||||
*
|
||||
* @return whether this suppression rule has CWE entries
|
||||
*/
|
||||
public boolean hasCwe() {
|
||||
return cwe.size() > 0;
|
||||
}
|
||||
/**
|
||||
* The list of cve entries to suppress.
|
||||
*/
|
||||
private List<String> cve = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Get the value of cve.
|
||||
*
|
||||
* @return the value of cve
|
||||
*/
|
||||
public List<String> getCve() {
|
||||
return cve;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cve.
|
||||
*
|
||||
* @param cve new value of cve
|
||||
*/
|
||||
public void setCve(List<String> cve) {
|
||||
this.cve = cve;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the cve to the cve list.
|
||||
*
|
||||
* @param cve the cve to add
|
||||
*/
|
||||
public void addCve(String cve) {
|
||||
this.cve.add(cve);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this suppression rule has CVE entries.
|
||||
*
|
||||
* @return whether this suppression rule has CVE entries
|
||||
*/
|
||||
public boolean hasCve() {
|
||||
return cve.size() > 0;
|
||||
}
|
||||
|
||||
public void process(Dependency dependency) {
|
||||
if (filePath != null && !filePath.matches(dependency.getFilePath())) {
|
||||
return;
|
||||
}
|
||||
if (sha1 != null && !sha1.equalsIgnoreCase(dependency.getSha1sum())) {
|
||||
return;
|
||||
}
|
||||
if (this.hasCpe()) {
|
||||
Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
Identifier i = itr.next();
|
||||
for (PropertyType c : this.cpe) {
|
||||
if (cpeMatches(c, i)) {
|
||||
itr.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasCve() || hasCwe() || hasCvssBelow()) {
|
||||
Iterator<Vulnerability> itr = dependency.getVulnerabilities().iterator();
|
||||
boolean remove = false;
|
||||
while (!remove && itr.hasNext()) {
|
||||
Vulnerability v = itr.next();
|
||||
for (String entry : this.cve) {
|
||||
if (entry.equalsIgnoreCase(v.getName())) {
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!remove) {
|
||||
for (String entry : this.cwe) {
|
||||
if (v.getCwe() != null) {
|
||||
final String toMatch = String.format("CWE-%s ", entry);
|
||||
final String toTest = v.getCwe().substring(0, toMatch.length()).toUpperCase();
|
||||
if (toTest.equals(toMatch)) {
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!remove) {
|
||||
for (float cvss : this.cvssBelow) {
|
||||
if (v.getCvssScore() < cvss) {
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean cpeHasNoVersion(PropertyType c) {
|
||||
if (c.isRegex()) {
|
||||
return false;
|
||||
} // cpe:/a:jboss:jboss:1.0.0:
|
||||
if (countCharacter(c.getValue(), ':') == 3) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int countCharacter(String str, char c) {
|
||||
int count = 0;
|
||||
int pos = str.indexOf(c) + 1;
|
||||
while (pos > 0) {
|
||||
count += 1;
|
||||
pos = str.indexOf(c, pos) + 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
boolean cpeMatches(PropertyType cpeEntry, Identifier identifier) {
|
||||
if (cpeEntry.matches(identifier.getValue())) {
|
||||
return true;
|
||||
} else if (cpeHasNoVersion(cpeEntry)) {
|
||||
if (cpeEntry.isCaseSensitive()) {
|
||||
if (identifier.getValue().startsWith(cpeEntry.getValue())) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
final String id = identifier.getValue().toLowerCase();
|
||||
final String check = cpeEntry.getValue().toLowerCase();
|
||||
if (id.startsWith(check)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.suppression;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class PropertyTypeTest {
|
||||
|
||||
public PropertyTypeTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of set and getValue method, of class PropertyType.
|
||||
*/
|
||||
@Test
|
||||
public void testSetGetValue() {
|
||||
|
||||
PropertyType instance = new PropertyType();
|
||||
String expResult = "test";
|
||||
instance.setValue(expResult);
|
||||
String result = instance.getValue();
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of isRegex method, of class PropertyType.
|
||||
*/
|
||||
@Test
|
||||
public void testIsRegex() {
|
||||
PropertyType instance = new PropertyType();
|
||||
boolean result = instance.isRegex();
|
||||
assertFalse(instance.isRegex());
|
||||
instance.setRegex(true);
|
||||
assertTrue(instance.isRegex());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of isCaseSensitive method, of class PropertyType.
|
||||
*/
|
||||
@Test
|
||||
public void testIsCaseSensitive() {
|
||||
PropertyType instance = new PropertyType();
|
||||
assertFalse(instance.isCaseSensitive());
|
||||
instance.setCaseSensitive(true);
|
||||
assertTrue(instance.isCaseSensitive());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of matches method, of class PropertyType.
|
||||
*/
|
||||
@Test
|
||||
public void testMatches() {
|
||||
String text = "Simple";
|
||||
|
||||
PropertyType instance = new PropertyType();
|
||||
instance.setValue("simple");
|
||||
assertTrue(instance.matches(text));
|
||||
instance.setCaseSensitive(true);
|
||||
assertFalse(instance.matches(text));
|
||||
|
||||
instance.setValue("s.*le");
|
||||
instance.setRegex(true);
|
||||
assertFalse(instance.matches(text));
|
||||
instance.setCaseSensitive(false);
|
||||
assertTrue(instance.matches(text));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.suppression;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class SuppressionHandlerTest {
|
||||
|
||||
public SuppressionHandlerTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getSupressionRules method, of class SuppressionHandler.
|
||||
*
|
||||
* @throws Exception thrown if there is an exception....
|
||||
*/
|
||||
@Test
|
||||
public void testHandler() throws Exception {
|
||||
File file = new File(this.getClass().getClassLoader().getResource("suppressions.xml").getPath());
|
||||
|
||||
File schema = new File(this.getClass().getClassLoader().getResource("schema/suppression.xsd").getPath());
|
||||
SuppressionHandler handler = new SuppressionHandler();
|
||||
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setValidating(true);
|
||||
SAXParser saxParser = factory.newSAXParser();
|
||||
saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_LANGUAGE, SuppressionParser.W3C_XML_SCHEMA);
|
||||
saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_SOURCE, schema);
|
||||
XMLReader xmlReader = saxParser.getXMLReader();
|
||||
xmlReader.setErrorHandler(new SuppressionErrorHandler());
|
||||
xmlReader.setContentHandler(handler);
|
||||
|
||||
InputStream inputStream = new FileInputStream(file);
|
||||
Reader reader = new InputStreamReader(inputStream); //, "UTF-8");
|
||||
InputSource in = new InputSource(reader);
|
||||
//in.setEncoding("UTF-8");
|
||||
|
||||
xmlReader.parse(in);
|
||||
|
||||
List result = handler.getSupressionRules();
|
||||
assertTrue(result.size() > 3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.suppression;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test of the suppression parser.
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class SuppressionParserTest {
|
||||
|
||||
public SuppressionParserTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of parseSuppressionRules method, of class SuppressionParser.
|
||||
*/
|
||||
@Test
|
||||
public void testParseSuppressionRules() throws Exception {
|
||||
File file = new File(this.getClass().getClassLoader().getResource("suppressions.xml").getPath());
|
||||
SuppressionParser instance = new SuppressionParser();
|
||||
List result = instance.parseSuppressionRules(file);
|
||||
assertTrue(result.size() > 3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Dependency-check-core is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* Dependency-check-core is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* dependency-check-core. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.suppression;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
|
||||
/**
|
||||
* Test of the suppression rule.
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
*/
|
||||
public class SuppressionRuleTest {
|
||||
|
||||
public SuppressionRuleTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Stupid tests of properties">
|
||||
/**
|
||||
* Test of FilePath property, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testFilePath() {
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
PropertyType expResult = new PropertyType();
|
||||
expResult.setValue("test");
|
||||
instance.setFilePath(expResult);
|
||||
PropertyType result = instance.getFilePath();
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of Sha1 property, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testSha1() {
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
String expResult = "384FAA82E193D4E4B0546059CA09572654BC3970";
|
||||
instance.setSha1(expResult);
|
||||
String result = instance.getSha1();
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of Cpe property, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testCpe() {
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
ArrayList<PropertyType> cpe = new ArrayList<PropertyType>();
|
||||
instance.setCpe(cpe);
|
||||
assertFalse(instance.hasCpe());
|
||||
PropertyType pt = new PropertyType();
|
||||
pt.setValue("one");
|
||||
instance.addCpe(pt);
|
||||
assertTrue(instance.hasCpe());
|
||||
List<PropertyType> result = instance.getCpe();
|
||||
assertEquals(cpe, result);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of CvssBelow property, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testGetCvssBelow() {
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
ArrayList<Float> cvss = new ArrayList<Float>();
|
||||
instance.setCvssBelow(cvss);
|
||||
assertFalse(instance.hasCvssBelow());
|
||||
instance.addCvssBelow(0.7f);
|
||||
assertTrue(instance.hasCvssBelow());
|
||||
List<Float> result = instance.getCvssBelow();
|
||||
assertEquals(cvss, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of Cwe property, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testCwe() {
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
ArrayList<String> cwe = new ArrayList<String>();
|
||||
instance.setCwe(cwe);
|
||||
assertFalse(instance.hasCwe());
|
||||
instance.addCwe("2");
|
||||
assertTrue(instance.hasCwe());
|
||||
List<String> result = instance.getCwe();
|
||||
assertEquals(cwe, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of Cve property, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testCve() {
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
ArrayList<String> cve = new ArrayList<String>();
|
||||
instance.setCve(cve);
|
||||
assertFalse(instance.hasCve());
|
||||
instance.addCve("CVE-2013-1337");
|
||||
assertTrue(instance.hasCve());
|
||||
List<String> result = instance.getCve();
|
||||
assertEquals(cve, result);
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Ignored duplicate tests, left in, as empty tests, so IDE doesn't re-generate them">
|
||||
/**
|
||||
* Test of getFilePath method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testGetFilePath() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of setFilePath method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testSetFilePath() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getSha1 method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testGetSha1() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of setSha1 method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testSetSha1() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getCpe method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testGetCpe() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of setCpe method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testSetCpe() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of addCpe method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testAddCpe() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of hasCpe method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testHasCpe() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of setCvssBelow method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testSetCvssBelow() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of addCvssBelow method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testAddCvssBelow() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of hasCvssBelow method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testHasCvssBelow() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getCwe method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testGetCwe() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of setCwe method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testSetCwe() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of addCwe method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testAddCwe() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of hasCwe method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testHasCwe() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getCve method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testGetCve() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of setCve method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testSetCve() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of addCve method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testAddCve() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of hasCve method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testHasCve() {
|
||||
//already tested, this is just left so the IDE doesn't recreate it.
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Test of cpeHasNoVersion method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testCpeHasNoVersion() {
|
||||
PropertyType c = new PropertyType();
|
||||
c.setValue("cpe:/a:microsoft:.net_framework:4.5");
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
assertFalse(instance.cpeHasNoVersion(c));
|
||||
c.setValue("cpe:/a:microsoft:.net_framework:");
|
||||
assertFalse(instance.cpeHasNoVersion(c));
|
||||
c.setValue("cpe:/a:microsoft:.net_framework");
|
||||
assertTrue(instance.cpeHasNoVersion(c));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of countCharacter method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testCountCharacter() {
|
||||
String str = "cpe:/a:microsoft:.net_framework:4.5";
|
||||
char c = ':';
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
int expResult = 4;
|
||||
int result = instance.countCharacter(str, c);
|
||||
assertEquals(expResult, result);
|
||||
str = "::";
|
||||
expResult = 2;
|
||||
result = instance.countCharacter(str, c);
|
||||
assertEquals(expResult, result);
|
||||
str = "these are not the characters you are looking for";
|
||||
expResult = 0;
|
||||
result = instance.countCharacter(str, c);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of cpeMatches method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testCpeMatches() {
|
||||
Identifier identifier = new Identifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
|
||||
PropertyType cpe = new PropertyType();
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework:4.5");
|
||||
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
boolean expResult = true;
|
||||
boolean result = instance.cpeMatches(cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework:4.0");
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("CPE:/a:microsoft:.net_framework:4.5");
|
||||
cpe.setCaseSensitive(true);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework");
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = true;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.*");
|
||||
cpe.setRegex(true);
|
||||
expResult = true;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("CPE:/a:microsoft:.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(true);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:apache:.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of process method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testProcess() {
|
||||
File struts = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath());
|
||||
Dependency dependency = new Dependency(struts);
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
String sha1 = dependency.getSha1sum();
|
||||
dependency.setSha1sum("384FAA82E193D4E4B0546059CA09572654BC3970");
|
||||
Vulnerability v = createVulnerability();
|
||||
dependency.addVulnerability(v);
|
||||
|
||||
//cwe
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
instance.setSha1(sha1);
|
||||
instance.addCwe("287");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
dependency.setSha1sum(sha1);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
|
||||
//cvss
|
||||
dependency.addVulnerability(v);
|
||||
instance = new SuppressionRule();
|
||||
instance.addCvssBelow(5f);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
instance.addCvssBelow(8f);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
|
||||
//cve
|
||||
dependency.addVulnerability(v);
|
||||
instance = new SuppressionRule();
|
||||
instance.addCve("CVE-2012-1337");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
instance.addCve("CVE-2013-1337");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
|
||||
//cpe
|
||||
instance = new SuppressionRule();
|
||||
PropertyType pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:microsoft:.net_framework:4.0");
|
||||
instance.addCpe(pt);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().size() == 1);
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:microsoft:.net_framework:4.5");
|
||||
instance.addCpe(pt);
|
||||
pt = new PropertyType();
|
||||
pt.setValue(".*");
|
||||
pt.setRegex(true);
|
||||
instance.setFilePath(pt);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().isEmpty());
|
||||
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:5.0", "some url not needed for this test");
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:microsoft:.net_framework");
|
||||
instance.addCpe(pt);
|
||||
assertTrue(dependency.getIdentifiers().size() == 3);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().isEmpty());
|
||||
}
|
||||
|
||||
private Vulnerability createVulnerability() {
|
||||
Vulnerability v = new Vulnerability();
|
||||
v.setCwe("CWE-287 Improper Authentication");
|
||||
v.setName("CVE-2013-1337");
|
||||
v.setCvssScore(7.5f);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user