diff --git a/README.txt b/README.txt index c5fe133e9..59883f98f 100644 --- a/README.txt +++ b/README.txt @@ -7,10 +7,10 @@ If found, it will generate a report linking to the associated CVE entries. Usage: $ mvn package $ cd target -$ java -jar DependencyCheck-0.2.3.jar -h -$ java -jar DependencyCheck-0.2.3.jar -a Testing -out . -scan ./test-classes/org.mortbay.jetty.jar -scan ./test-classes/struts2-core-2.1.2.jar -scan ./lib +$ java -jar DependencyCheck-0.2.3.1.jar -h +$ java -jar DependencyCheck-0.2.3.1.jar -a Testing -out . -scan ./test-classes/org.mortbay.jetty.jar -scan ./test-classes/struts2-core-2.1.2.jar -scan ./lib -Then load the resulting 'Testing.html' into your favorite browser. +Then load the resulting 'DependencyCheck-Report.html' into your favorite browser. Author: Jeremy Long (jeremy.long@gmail.com) diff --git a/pom.xml b/pom.xml index e81a40003..6122e2ad9 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ along with DependencyCheck. If not, see . org.codesecure DependencyCheck - 0.2.3 + 0.2.3.1 jar DependencyCheck @@ -100,7 +100,7 @@ along with DependencyCheck. If not, see . maven-javadoc-plugin 2.8.1 - Copyright © 2012 Jeremy Long. All Rights Reserved. + Copyright© 2012 Jeremy Long. All Rights Reserved. @@ -451,5 +451,14 @@ along with DependencyCheck. If not, see . hawtdb 1.6 --> + + + + diff --git a/src/main/java/org/codesecure/dependencycheck/App.java b/src/main/java/org/codesecure/dependencycheck/App.java index ca24abc73..9f726c0dc 100644 --- a/src/main/java/org/codesecure/dependencycheck/App.java +++ b/src/main/java/org/codesecure/dependencycheck/App.java @@ -28,7 +28,6 @@ import java.util.logging.LogManager; import java.util.logging.Logger; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.cli.ParseException; -import org.codesecure.dependencycheck.analyzer.AnalysisPhase; import org.codesecure.dependencycheck.data.cpe.xml.Importer; import org.codesecure.dependencycheck.reporting.ReportGenerator; import org.codesecure.dependencycheck.dependency.Dependency; diff --git a/src/main/java/org/codesecure/dependencycheck/Engine.java b/src/main/java/org/codesecure/dependencycheck/Engine.java index 11a8a1b42..1eb2c9b9d 100644 --- a/src/main/java/org/codesecure/dependencycheck/Engine.java +++ b/src/main/java/org/codesecure/dependencycheck/Engine.java @@ -195,7 +195,7 @@ public class Engine { try { a.initialize(); } catch (Exception ex) { - Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, + Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, "Exception occured initializing " + a.getName() + ".", ex); try { a.close(); @@ -255,7 +255,7 @@ public class Engine { try { source.update(); } catch (UpdateException ex) { - Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, + Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, "Unable to update " + source.getClass().getName(), ex); } } diff --git a/src/main/java/org/codesecure/dependencycheck/analyzer/JarAnalyzer.java b/src/main/java/org/codesecure/dependencycheck/analyzer/JarAnalyzer.java index 6e2bb5ab2..db5cd4597 100644 --- a/src/main/java/org/codesecure/dependencycheck/analyzer/JarAnalyzer.java +++ b/src/main/java/org/codesecure/dependencycheck/analyzer/JarAnalyzer.java @@ -186,6 +186,7 @@ public class JarAnalyzer extends AbstractAnalyzer { parseManifest(dependency); analyzePackageNames(dependency); analyzePOM(dependency); + addPredefinedData(dependency); } catch (IOException ex) { throw new AnalysisException("Exception occured reading the JAR file.", ex); } catch (JAXBException ex) { @@ -615,4 +616,15 @@ public class JarAnalyzer extends AbstractAnalyzer { sb.append(text.substring(end + 1)); return interpolateString(sb.toString(), properties); //yes yes, this should be a loop... } + + private void addPredefinedData(Dependency dependency) { + Evidence spring = new Evidence("Manifest", + "Implementation-Title", + "Spring Framework", + Evidence.Confidence.HIGH); + + if (dependency.getProductEvidence().getEvidence().contains(spring)) { + dependency.getVendorEvidence().addEvidence("a priori", "vendor", "SpringSource", Evidence.Confidence.HIGH); + } + } } diff --git a/src/main/java/org/codesecure/dependencycheck/data/cpe/CPEAnalyzer.java b/src/main/java/org/codesecure/dependencycheck/data/cpe/CPEAnalyzer.java index 8a8306c8f..822f54031 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/cpe/CPEAnalyzer.java +++ b/src/main/java/org/codesecure/dependencycheck/data/cpe/CPEAnalyzer.java @@ -149,23 +149,11 @@ public class CPEAnalyzer implements org.codesecure.dependencycheck.analyzer.Anal Confidence versionConf = Confidence.HIGH; String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), vendorConf); - //dependency.getVendorEvidence().toString(vendorConf); -// if ("".equals(vendors)) { -// vendors = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX; -// } String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), productConf); - ///dependency.getProductEvidence().toString(productConf); -// if ("".equals(products)) { -// products = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX; -// } String versions = addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), versionConf); - //dependency.getVersionEvidence().toString(versionConf); -// if ("".equals(versions)) { -// versions = STRING_THAT_WILL_NEVER_BE_IN_THE_INDEX; -// } boolean found = false; - int cnt = 0; + int ctr = 0; do { List entries = searchCPE(vendors, products, versions, dependency.getProductEvidence().getWeighting(), dependency.getVendorEvidence().getWeighting()); @@ -186,14 +174,14 @@ public class CPEAnalyzer implements org.codesecure.dependencycheck.analyzer.Anal if (!found) { - int round = cnt % 3; + int round = ctr % 3; if (round == 0) { vendorConf = reduceConfidence(vendorConf); if (dependency.getVendorEvidence().contains(vendorConf)) { //vendors += " " + dependency.getVendorEvidence().toString(vendorConf); vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), vendorConf); } else { - cnt += 1; + ctr += 1; round += 1; } } @@ -203,7 +191,7 @@ public class CPEAnalyzer implements org.codesecure.dependencycheck.analyzer.Anal //products += " " + dependency.getProductEvidence().toString(productConf); products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), productConf); } else { - cnt += 1; + ctr += 1; round += 1; } } @@ -215,7 +203,7 @@ public class CPEAnalyzer implements org.codesecure.dependencycheck.analyzer.Anal } } } - } while (!found && (++cnt) < 9); + } while (!found && (++ctr) < 9); } /** diff --git a/src/main/java/org/codesecure/dependencycheck/data/cpe/Entry.java b/src/main/java/org/codesecure/dependencycheck/data/cpe/Entry.java index ce015763f..d42b8e552 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/cpe/Entry.java +++ b/src/main/java/org/codesecure/dependencycheck/data/cpe/Entry.java @@ -45,17 +45,12 @@ public class Entry { public static Entry parse(Document doc) { Entry entry = new Entry(); try { - entry.setName(doc.get(Fields.NAME)); + entry.parseName(doc.get(Fields.NAME)); entry.setTitle(doc.get(Fields.TITLE)); } catch (UnsupportedEncodingException ex) { Logger.getLogger(Entry.class.getName()).log(Level.SEVERE, null, ex); entry.name = doc.get(Fields.NAME); } -// entry.vendor = doc.get(Fields.VENDOR); -// entry.version = doc.get(Fields.VERSION); -// //entry.revision = doc.get(Fields.REVISION); -// entry.product = doc.get(Fields.TITLE); -// entry.nvdId = doc.get(Fields.NVDID); return entry; } /** @@ -95,15 +90,12 @@ public class Entry { } /** - * Set the value of name and calls parseName to obtain the - * vendor:product:version:revision + * Set the value of name * * @param name new value of name - * @throws UnsupportedEncodingException should never be thrown... */ - public void setName(String name) throws UnsupportedEncodingException { + public void setName(String name) { this.name = name; - parseName(); } /** * The status of the CPE Entry. @@ -310,15 +302,17 @@ public class Entry { *

Results in:

  • Vendor: apache
  • Product: struts
  • *
  • Version: 1.1
  • Revision: rc2
* + * @param cpeName the cpe name * @throws UnsupportedEncodingException should never be thrown... */ - private void parseName() throws UnsupportedEncodingException { - if (name != null && name.length() > 7) { - String[] data = name.substring(7).split(":"); + public void parseName(String cpeName) throws UnsupportedEncodingException { + this.name = cpeName; + if (cpeName != null && cpeName.length() > 7) { + String[] data = cpeName.substring(7).split(":"); if (data.length >= 1) { - vendor = URLDecoder.decode(data[0], "UTF-8"); + vendor = URLDecoder.decode(data[0], "UTF-8").replaceAll("[_-]", " "); if (data.length >= 2) { - product = URLDecoder.decode(data[1], "UTF-8"); + product = URLDecoder.decode(data[1], "UTF-8").replaceAll("[_-]", " "); if (data.length >= 3) { version = URLDecoder.decode(data[2], "UTF-8"); if (data.length >= 4) { diff --git a/src/main/java/org/codesecure/dependencycheck/data/cpe/Index.java b/src/main/java/org/codesecure/dependencycheck/data/cpe/Index.java index 6a057de12..b52e0e4cb 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/cpe/Index.java +++ b/src/main/java/org/codesecure/dependencycheck/data/cpe/Index.java @@ -100,6 +100,11 @@ public class Index extends AbstractIndex implements CachedWebDataSource { } File path = new File(exePath.getCanonicalFile() + File.separator + fileName); path = new File(path.getCanonicalPath()); + if (!path.exists()) { + if (!path.mkdirs()) { + throw new IOException("Unable to create CPE Data directory"); + } + } return path; } @@ -113,6 +118,7 @@ public class Index extends AbstractIndex implements CachedWebDataSource { Map fieldAnalyzers = new HashMap(); fieldAnalyzers.put(Fields.VERSION, new KeywordAnalyzer()); + fieldAnalyzers.put(Fields.NAME, new KeywordAnalyzer()); PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper( new StandardAnalyzer(Version.LUCENE_35), fieldAnalyzers); diff --git a/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/CPEHandler.java b/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/CPEHandler.java index 085b15b63..076bf406c 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/CPEHandler.java +++ b/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/CPEHandler.java @@ -66,7 +66,7 @@ public class CPEHandler extends DefaultHandler { skip = (temp != null && temp.equals("true")); try { if (!skip && name.startsWith("cpe:/a:")) { - entry.setName(name); + entry.parseName(name); } else { skip = true; } diff --git a/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/Indexer.java b/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/Indexer.java index 4f350fa66..39870bf0e 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/Indexer.java +++ b/src/main/java/org/codesecure/dependencycheck/data/cpe/xml/Indexer.java @@ -27,7 +27,6 @@ import org.apache.lucene.index.Term; import org.codesecure.dependencycheck.data.cpe.Entry; import org.codesecure.dependencycheck.data.cpe.Fields; import org.codesecure.dependencycheck.data.cpe.Index; -import org.codesecure.dependencycheck.data.lucene.LuceneUtils; /** * The Indexer is used to convert a CPE Entry, retrieved from the CPE XML file, @@ -46,7 +45,8 @@ public class Indexer extends Index implements EntrySaveDelegate { */ public void saveEntry(Entry entry) throws CorruptIndexException, IOException { Document doc = convertEntryToDoc(entry); - Term term = new Term(Fields.NVDID, LuceneUtils.escapeLuceneQuery(entry.getNvdId())); + //Term term = new Term(Fields.NVDID, LuceneUtils.escapeLuceneQuery(entry.getNvdId())); + Term term = new Term(Fields.NAME, entry.getName()); indexWriter.updateDocument(term, doc); } diff --git a/src/main/java/org/codesecure/dependencycheck/data/nvdcve/Index.java b/src/main/java/org/codesecure/dependencycheck/data/nvdcve/Index.java index d544acd60..ebf5c5974 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/nvdcve/Index.java +++ b/src/main/java/org/codesecure/dependencycheck/data/nvdcve/Index.java @@ -98,6 +98,11 @@ public class Index extends AbstractIndex implements CachedWebDataSource { } File path = new File(exePath.getCanonicalFile() + File.separator + fileName); path = new File(path.getCanonicalPath()); + if (!path.exists()) { + if (!path.mkdirs()) { + throw new IOException("Unable to create NVD CVE Data directory"); + } + } return path; } diff --git a/src/main/java/org/codesecure/dependencycheck/data/nvdcve/xml/Importer.java b/src/main/java/org/codesecure/dependencycheck/data/nvdcve/xml/Importer.java index f75bf4d3a..6eabad440 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/nvdcve/xml/Importer.java +++ b/src/main/java/org/codesecure/dependencycheck/data/nvdcve/xml/Importer.java @@ -43,15 +43,17 @@ public class Importer { */ public static void importXML(File file) { NvdCveParser indexer = null; + org.codesecure.dependencycheck.data.cpe.xml.Indexer cpeIndexer = null; try { - indexer = new NvdCveParser(); - indexer.openIndexWriter(); + //HACK - hack to ensure all CPE data is stored in the index. + cpeIndexer = new org.codesecure.dependencycheck.data.cpe.xml.Indexer(); + cpeIndexer.openIndexWriter(); + indexer.setCPEIndexer(cpeIndexer); indexer.parse(file); - } catch (CorruptIndexException ex) { Logger.getLogger(Importer.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { @@ -60,6 +62,9 @@ public class Importer { if (indexer != null) { indexer.close(); } + if (cpeIndexer != null) { + cpeIndexer.close(); + } } } // public static void importXML(File file) throws FileNotFoundException, IOException, JAXBException, diff --git a/src/main/java/org/codesecure/dependencycheck/data/nvdcve/xml/NvdCveParser.java b/src/main/java/org/codesecure/dependencycheck/data/nvdcve/xml/NvdCveParser.java index ec11f3ff6..bf086beca 100644 --- a/src/main/java/org/codesecure/dependencycheck/data/nvdcve/xml/NvdCveParser.java +++ b/src/main/java/org/codesecure/dependencycheck/data/nvdcve/xml/NvdCveParser.java @@ -23,14 +23,17 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; +import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.FieldInfo.IndexOptions; import org.apache.lucene.index.Term; +import org.codesecure.dependencycheck.data.cpe.Entry; import org.codesecure.dependencycheck.data.nvdcve.Fields; import org.codesecure.dependencycheck.data.nvdcve.Index; @@ -40,6 +43,19 @@ import org.codesecure.dependencycheck.data.nvdcve.Index; */ public class NvdCveParser extends Index { + //HACK - this has initially been placed here as a hack because not all + // of the CPEs listed in the NVD CVE are actually in the CPE xml file + // hosted by NIST. + private org.codesecure.dependencycheck.data.cpe.xml.Indexer cpeIndexer = null; + + /** + * Adds the CPE Index to add additional CPEs found by parsing the NVD CVE. + * @param indexer the CPE Indexer to write new CPEs into. + */ + public void setCPEIndexer(org.codesecure.dependencycheck.data.cpe.xml.Indexer indexer) { + this.cpeIndexer = indexer; + } + /** * Parses an NVD CVE xml file using a buffered readerd. This * method maybe more fragile then using a partial-unmarshalling SAX @@ -164,10 +180,27 @@ public class NvdCveParser extends Index { * Adds a CPE to the Lucene Document * @param cpe a string representing a CPE * @param doc a lucene document + * @throws CorruptIndexException is thrown if the CPE Index is corrupt + * @throws IOException is thrown if there is an IO Exception while writting to the CPE Index */ - private void addVulnerableCpe(String cpe, Document doc) { + private void addVulnerableCpe(String cpe, Document doc) throws CorruptIndexException, IOException { Field vulnerable = new Field(Fields.VULNERABLE_CPE, cpe, Field.Store.NO, Field.Index.ANALYZED); vulnerable.setIndexOptions(IndexOptions.DOCS_ONLY); doc.add(vulnerable); + + //HACK - this has initially been placed here as a hack because not all + // of the CPEs listed in the NVD CVE are actually in the CPE xml file + // hosted by NIST. + Entry cpeEntry = new Entry(); + try { + cpeEntry.parseName(cpe); + cpeEntry.setNvdId("0"); + cpeEntry.setTitle(cpe); + } catch (UnsupportedEncodingException ex) { + Logger.getLogger(NvdCveParser.class.getName()).log(Level.SEVERE, null, ex); + } + if (cpeIndexer != null) { + cpeIndexer.saveEntry(cpeEntry); + } } } diff --git a/src/main/java/org/codesecure/dependencycheck/dependency/EvidenceCollection.java b/src/main/java/org/codesecure/dependencycheck/dependency/EvidenceCollection.java index 13650c495..f710d85b2 100644 --- a/src/main/java/org/codesecure/dependencycheck/dependency/EvidenceCollection.java +++ b/src/main/java/org/codesecure/dependencycheck/dependency/EvidenceCollection.java @@ -184,7 +184,7 @@ public class EvidenceCollection implements Iterable { text = text.toLowerCase(); for (Evidence e : this.list) { - if (e.used && e.value.contains(text)) { + if (e.used && e.value.toLowerCase().contains(text)) { return true; } } diff --git a/src/main/java/org/codesecure/dependencycheck/utils/CliParser.java b/src/main/java/org/codesecure/dependencycheck/utils/CliParser.java index 6eedcb4be..4cb7c0b86 100644 --- a/src/main/java/org/codesecure/dependencycheck/utils/CliParser.java +++ b/src/main/java/org/codesecure/dependencycheck/utils/CliParser.java @@ -326,7 +326,7 @@ public final class CliParser { * @return if auto-update is allowed. */ public boolean isAutoUpdate() { - return (line != null) ? !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE) : false; + return (line != null) ? !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE) : true; } /** diff --git a/src/main/resources/templates/HtmlReport.vsl b/src/main/resources/templates/HtmlReport.vsl index 9316b6586..8723fbc03 100644 --- a/src/main/resources/templates/HtmlReport.vsl +++ b/src/main/resources/templates/HtmlReport.vsl @@ -34,7 +34,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.