fixed JarAnalyzer so it grabs more data from the JAR.

This commit is contained in:
Jeremy Long
2012-09-09 00:17:42 -04:00
parent dd4b13d318
commit dbc10e53e4
2 changed files with 94 additions and 63 deletions

11
pom.xml
View File

@@ -27,12 +27,21 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses/>.
<packaging>jar</packaging> <packaging>jar</packaging>
<name>DependencyCheck</name> <name>DependencyCheck</name>
<url>http://maven.apache.org</url> <url>http://codesecure.blogspot.com</url>
<description>DependencyCheck is a simple utility that attempts to determine if there is a Common Product Enumeration (CPE) identifier for a given project dependency. If found, it will generate a report linking to the associated CVE entries.</description> <description>DependencyCheck is a simple utility that attempts to determine if there is a Common Product Enumeration (CPE) identifier for a given project dependency. If found, it will generate a report linking to the associated CVE entries.</description>
<organization>
<name>Jeremy Long</name>
</organization>
<developers> <developers>
<developer> <developer>
<name>Jeremy Long</name> <name>Jeremy Long</name>
<email>jeremy.long@gmail.com</email> <email>jeremy.long@gmail.com</email>
<organization>Codesecure</organization>
<organizationUrl>http://codesecure.blogspot.com</organizationUrl>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
</developer> </developer>
</developers> </developers>
<scm> <scm>

View File

@@ -23,6 +23,7 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map.Entry;
import java.util.jar.Attributes; import java.util.jar.Attributes;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.jar.Manifest; import java.util.jar.Manifest;
@@ -46,21 +47,44 @@ import org.codesecure.dependencycheck.utils.Checksum;
*/ */
public class JarAnalyzer implements Analyzer { public class JarAnalyzer implements Analyzer {
/**
* item in some manifest, should be considered medium confidence.
*/
private static final String BUNDLE_VERSION = "Bundle-Version"; //: 2.1.2 private static final String BUNDLE_VERSION = "Bundle-Version"; //: 2.1.2
/**
* item in some manifest, should be considered medium confidence.
*/
private static final String BUNDLE_DESCRIPTION = "Bundle-Description"; //: Apache Struts 2 private static final String BUNDLE_DESCRIPTION = "Bundle-Description"; //: Apache Struts 2
/**
* item in some manifest, should be considered medium confidence.
*/
private static final String BUNDLE_NAME = "Bundle-Name"; //: Struts 2 Core private static final String BUNDLE_NAME = "Bundle-Name"; //: Struts 2 Core
/**
* item in some manifest, should be considered medium confidence.
*/
private static final String BUNDLE_VENDOR = "Bundle-Vendor"; //: Apache Software Foundation private static final String BUNDLE_VENDOR = "Bundle-Vendor"; //: Apache Software Foundation
/**
* An enumeration to keep track of the characters in a string as it is being
* read in one character at a time.
*/
private enum STRING_STATE { private enum STRING_STATE {
ALPHA, ALPHA,
NUMBER, NUMBER,
PERIOD,
OTHER OTHER
} }
/**
* Determines type of the character passed in.
* @param c a character
* @return a STRING_STATE representing whether the character is number, alpha, or other.
*/
private STRING_STATE determineState(char c) { private STRING_STATE determineState(char c) {
if (c >= '0' && c <= '9' || c == '.') { if (c >= '0' && c <= '9') {
return STRING_STATE.NUMBER; return STRING_STATE.NUMBER;
} else if (c == '.') {
return STRING_STATE.PERIOD;
} else if (c >= 'a' && c <= 'z') { } else if (c >= 'a' && c <= 'z') {
return STRING_STATE.ALPHA; return STRING_STATE.ALPHA;
} else { } else {
@@ -83,8 +107,11 @@ public class JarAnalyzer implements Analyzer {
String fileName = file.getName(); String fileName = file.getName();
dependency.setFileName(fileName); dependency.setFileName(fileName);
dependency.setFilePath(file.getCanonicalPath()); dependency.setFilePath(file.getCanonicalPath());
String fileNameEvidence = fileName.substring(0, fileName.length() - 4)
.toLowerCase().replace('-', ' ').replace('_', ' '); //slightly process the filename to chunk it into distinct words, numbers.
// Yes, the lucene analyzer might do this, but I want a little better control
// over the process.
String fileNameEvidence = fileName.substring(0, fileName.length() - 4).toLowerCase().replace('-', ' ').replace('_', ' ');
StringBuilder sb = new StringBuilder(fileNameEvidence.length()); StringBuilder sb = new StringBuilder(fileNameEvidence.length());
STRING_STATE state = determineState(fileNameEvidence.charAt(0)); STRING_STATE state = determineState(fileNameEvidence.charAt(0));
@@ -92,9 +119,14 @@ public class JarAnalyzer implements Analyzer {
char c = fileNameEvidence.charAt(i); char c = fileNameEvidence.charAt(i);
STRING_STATE newState = determineState(c); STRING_STATE newState = determineState(c);
if (newState != state) { if (newState != state) {
sb.append(' '); if ((state != STRING_STATE.NUMBER && newState == STRING_STATE.PERIOD)
state = newState; || (state == STRING_STATE.PERIOD && newState != STRING_STATE.NUMBER)
|| (state == STRING_STATE.ALPHA || newState == STRING_STATE.ALPHA)
|| ((state == STRING_STATE.OTHER || newState == STRING_STATE.OTHER) && c != ' ')) {
sb.append(' ');
}
} }
state = newState;
sb.append(c); sb.append(c);
} }
Pattern rx = Pattern.compile("\\s\\s+"); Pattern rx = Pattern.compile("\\s\\s+");
@@ -307,58 +339,48 @@ public class JarAnalyzer implements Analyzer {
EvidenceCollection versionEvidence = dependency.getVendorEvidence(); EvidenceCollection versionEvidence = dependency.getVendorEvidence();
String source = "Manifest"; String source = "Manifest";
String name = Attributes.Name.IMPLEMENTATION_TITLE.toString();
String value = atts.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
if (value != null) {
titleEvidence.addEvidence(source, name, value, Evidence.Confidence.HIGH);
}
name = Attributes.Name.IMPLEMENTATION_VERSION.toString(); for (Entry<Object, Object> entry : atts.entrySet()) {
value = atts.getValue(Attributes.Name.IMPLEMENTATION_VERSION); String key = entry.getKey().toString();
if (value != null) { String value = atts.getValue(key);
versionEvidence.addEvidence(source, name, value, Evidence.Confidence.HIGH); if (key.equals(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
} titleEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH);
} else if (key.equals(Attributes.Name.IMPLEMENTATION_VERSION.toString())) {
name = Attributes.Name.IMPLEMENTATION_VENDOR.toString(); versionEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH);
value = atts.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); } else if (key.equals(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) {
if (value != null) { vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH);
vendorEvidence.addEvidence(source, name, value, Evidence.Confidence.HIGH); } else if (key.equals(Attributes.Name.IMPLEMENTATION_VENDOR_ID.toString())) {
} vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
} else if (key.equals(BUNDLE_DESCRIPTION)) {
name = Attributes.Name.IMPLEMENTATION_VENDOR_ID.toString(); titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
value = atts.getValue(Attributes.Name.IMPLEMENTATION_VENDOR_ID); } else if (key.equals(BUNDLE_NAME)) {
if (value != null) { titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
vendorEvidence.addEvidence(source, name, value, Evidence.Confidence.MEDIUM); } else if (key.equals(BUNDLE_VENDOR)) {
} vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH);
} else if (key.equals(BUNDLE_VERSION)) {
name = BUNDLE_DESCRIPTION; versionEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH);
value = atts.getValue(BUNDLE_DESCRIPTION); } else if (key.equals(Attributes.Name.MAIN_CLASS.toString())) {
if (value != null) { titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
titleEvidence.addEvidence(source, name, value, Evidence.Confidence.MEDIUM); vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
} } else {
key = key.toLowerCase();
name = BUNDLE_VENDOR; if (key.contains("version")) {
value = atts.getValue(BUNDLE_VENDOR); versionEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
if (value != null) { } else if (key.contains("title")) {
vendorEvidence.addEvidence(source, name, value, Evidence.Confidence.MEDIUM); titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
} } else if (key.contains("vendor")) {
vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
name = BUNDLE_VERSION; } else if (key.contains("name")) {
value = atts.getValue(BUNDLE_VERSION); titleEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
if (value != null) { vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.MEDIUM);
versionEvidence.addEvidence(source, name, value, Evidence.Confidence.MEDIUM); } else {
} titleEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW);
name = BUNDLE_NAME; vendorEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW);
value = atts.getValue(BUNDLE_NAME); if (value.matches(".*\\d.*")) {
if (value != null) { versionEvidence.addEvidence(source, key, value, Evidence.Confidence.LOW);
titleEvidence.addEvidence(source, name, value, Evidence.Confidence.LOW); }
} }
}
name = Attributes.Name.MAIN_CLASS.toString();
value = atts.getValue(Attributes.Name.MAIN_CLASS);
if (value != null) {
titleEvidence.addEvidence(source, name, value, Evidence.Confidence.MEDIUM);
vendorEvidence.addEvidence(source, name, value, Evidence.Confidence.MEDIUM);
} }
} }
} }