Coverage Report - org.owasp.dependencycheck.data.nvdcve.xml.NvdCve20Handler
 
Classes in this File Line Coverage Branch Coverage Complexity
NvdCve20Handler
76%
97/126
84%
73/86
3
NvdCve20Handler$Element
94%
18/19
N/A
3
 
 1  
 /*
 2  
  * This file is part of dependency-check-core.
 3  
  *
 4  
  * Dependency-check-core is free software: you can redistribute it and/or modify it
 5  
  * under the terms of the GNU General Public License as published by the Free
 6  
  * Software Foundation, either version 3 of the License, or (at your option) any
 7  
  * later version.
 8  
  *
 9  
  * Dependency-check-core is distributed in the hope that it will be useful, but
 10  
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 12  
  * details.
 13  
  *
 14  
  * You should have received a copy of the GNU General Public License along with
 15  
  * dependency-check-core. If not, see http://www.gnu.org/licenses/.
 16  
  *
 17  
  * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
 18  
  */
 19  
 package org.owasp.dependencycheck.data.nvdcve.xml;
 20  
 
 21  
 import java.io.IOException;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 import java.util.logging.Level;
 25  
 import java.util.logging.Logger;
 26  
 import org.apache.lucene.index.CorruptIndexException;
 27  
 import org.owasp.dependencycheck.data.cpe.Index;
 28  
 import org.owasp.dependencycheck.data.nvdcve.CveDB;
 29  
 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
 30  
 import org.owasp.dependencycheck.dependency.Reference;
 31  
 import org.owasp.dependencycheck.dependency.Vulnerability;
 32  
 import org.owasp.dependencycheck.dependency.VulnerableSoftware;
 33  
 import org.xml.sax.Attributes;
 34  
 import org.xml.sax.SAXException;
 35  
 import org.xml.sax.SAXNotSupportedException;
 36  
 import org.xml.sax.helpers.DefaultHandler;
 37  
 
 38  
 /**
 39  
  * A SAX Handler that will parse the NVD CVE XML (schema version 2.0).
 40  
  *
 41  
  * @author Jeremy Long (jeremy.long@owasp.org)
 42  
  */
 43  3
 public class NvdCve20Handler extends DefaultHandler {
 44  
 
 45  
     /**
 46  
      * the current supported schema version.
 47  
      */
 48  
     private static final String CURRENT_SCHEMA_VERSION = "2.0";
 49  
     /**
 50  
      * the current element.
 51  
      */
 52  3
     private final Element current = new Element();
 53  
     /**
 54  
      * the text of the node.
 55  
      */
 56  
     private StringBuilder nodeText;
 57  
     /**
 58  
      * the vulnerability.
 59  
      */
 60  
     private Vulnerability vulnerability;
 61  
     /**
 62  
      * a reference for the cve.
 63  
      */
 64  
     private Reference reference;
 65  
     /**
 66  
      * flag indicating whether the application has a cpe.
 67  
      */
 68  3
     private boolean hasApplicationCpe = false;
 69  
     /**
 70  
      * The total number of entries parsed.
 71  
      */
 72  
     private int totalNumberOfEntries;
 73  
 
 74  
     /**
 75  
      * Get the value of totalNumberOfEntries.
 76  
      *
 77  
      * @return the value of totalNumberOfEntries
 78  
      */
 79  
     public int getTotalNumberOfEntries() {
 80  0
         return totalNumberOfEntries;
 81  
     }
 82  
     /**
 83  
      * The total number of application entries parsed.
 84  
      */
 85  
     private int totalNumberOfApplicationEntries;
 86  
 
 87  
     /**
 88  
      * Get the value of totalNumberOfApplicationEntries.
 89  
      *
 90  
      * @return the value of totalNumberOfApplicationEntries
 91  
      */
 92  
     public int getTotalNumberOfApplicationEntries() {
 93  0
         return totalNumberOfApplicationEntries;
 94  
     }
 95  
 
 96  
     @Override
 97  
     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
 98  7236
         current.setNode(qName);
 99  7236
         if (current.isEntryNode()) {
 100  81
             hasApplicationCpe = false;
 101  81
             vulnerability = new Vulnerability();
 102  81
             vulnerability.setName(attributes.getValue("id"));
 103  7155
         } else if (current.isVulnProductNode()) {
 104  2181
             nodeText = new StringBuilder(100);
 105  4974
         } else if (current.isVulnReferencesNode()) {
 106  270
             final String lang = attributes.getValue("xml:lang");
 107  270
             if ("en".equals(lang)) {
 108  270
                 reference = new Reference();
 109  
             } else {
 110  0
                 reference = null;
 111  
             }
 112  270
         } else if (reference != null && current.isVulnReferenceNode()) {
 113  270
             reference.setUrl(attributes.getValue("href"));
 114  270
             nodeText = new StringBuilder(130);
 115  4434
         } else if (reference != null && current.isVulnSourceNode()) {
 116  270
             nodeText = new StringBuilder(30);
 117  4164
         } else if (current.isVulnSummaryNode()) {
 118  81
             nodeText = new StringBuilder(500);
 119  4083
         } else if (current.isNVDNode()) {
 120  3
             final String nvdVer = attributes.getValue("nvd_xml_version");
 121  3
             if (!CURRENT_SCHEMA_VERSION.equals(nvdVer)) {
 122  0
                 throw new SAXNotSupportedException("Schema version " + nvdVer + " is not supported");
 123  
             }
 124  3
         } else if (current.isVulnCWENode()) {
 125  57
             vulnerability.setCwe(attributes.getValue("id"));
 126  4023
         } else if (current.isCVSSScoreNode()) {
 127  78
             nodeText = new StringBuilder(5);
 128  3945
         } else if (current.isCVSSAccessVectorNode()) {
 129  78
             nodeText = new StringBuilder(20);
 130  3867
         } else if (current.isCVSSAccessComplexityNode()) {
 131  78
             nodeText = new StringBuilder(20);
 132  3789
         } else if (current.isCVSSAuthenticationNode()) {
 133  78
             nodeText = new StringBuilder(20);
 134  3711
         } else if (current.isCVSSAvailabilityImpactNode()) {
 135  78
             nodeText = new StringBuilder(20);
 136  3633
         } else if (current.isCVSSConfidentialityImpactNode()) {
 137  78
             nodeText = new StringBuilder(20);
 138  3555
         } else if (current.isCVSSIntegrityImpactNode()) {
 139  78
             nodeText = new StringBuilder(20);
 140  
         }
 141  7236
     }
 142  
 
 143  
     @Override
 144  
     public void characters(char[] ch, int start, int length) throws SAXException {
 145  11883
         if (nodeText != null) {
 146  3372
             nodeText.append(ch, start, length);
 147  
         }
 148  11883
     }
 149  
 
 150  
     @Override
 151  
     public void endElement(String uri, String localName, String qName) throws SAXException {
 152  7236
         current.setNode(qName);
 153  7236
         if (current.isEntryNode()) {
 154  81
             totalNumberOfEntries += 1;
 155  81
             if (hasApplicationCpe) {
 156  54
                 totalNumberOfApplicationEntries += 1;
 157  
                 try {
 158  54
                     saveEntry(vulnerability);
 159  0
                 } catch (DatabaseException ex) {
 160  0
                     throw new SAXException(ex);
 161  0
                 } catch (CorruptIndexException ex) {
 162  0
                     throw new SAXException(ex);
 163  0
                 } catch (IOException ex) {
 164  0
                     throw new SAXException(ex);
 165  54
                 }
 166  
             }
 167  81
             vulnerability = null;
 168  7155
         } else if (current.isCVSSScoreNode()) {
 169  
             try {
 170  78
                 final float score = Float.parseFloat(nodeText.toString());
 171  78
                 vulnerability.setCvssScore(score);
 172  0
             } catch (NumberFormatException ex) {
 173  0
                 Logger.getLogger(NvdCve20Handler.class.getName()).log(Level.SEVERE, "Error parsing CVSS Score.");
 174  0
                 Logger.getLogger(NvdCve20Handler.class.getName()).log(Level.FINE, null, ex);
 175  78
             }
 176  78
             nodeText = null;
 177  7077
         } else if (current.isCVSSAccessVectorNode()) {
 178  78
             vulnerability.setCvssAccessVector(nodeText.toString());
 179  78
             nodeText = null;
 180  6999
         } else if (current.isCVSSAccessComplexityNode()) {
 181  78
             vulnerability.setCvssAccessComplexity(nodeText.toString());
 182  78
             nodeText = null;
 183  6921
         } else if (current.isCVSSAuthenticationNode()) {
 184  78
             vulnerability.setCvssAuthentication(nodeText.toString());
 185  78
             nodeText = null;
 186  6843
         } else if (current.isCVSSAvailabilityImpactNode()) {
 187  78
             vulnerability.setCvssAvailabilityImpact(nodeText.toString());
 188  78
             nodeText = null;
 189  6765
         } else if (current.isCVSSConfidentialityImpactNode()) {
 190  78
             vulnerability.setCvssConfidentialityImpact(nodeText.toString());
 191  78
             nodeText = null;
 192  6687
         } else if (current.isCVSSIntegrityImpactNode()) {
 193  78
             vulnerability.setCvssIntegrityImpact(nodeText.toString());
 194  78
             nodeText = null;
 195  6609
         } else if (current.isVulnProductNode()) {
 196  2181
             final String cpe = nodeText.toString();
 197  2181
             if (cpe.startsWith("cpe:/a:")) {
 198  1842
                 hasApplicationCpe = true;
 199  1842
                 vulnerability.addVulnerableSoftware(cpe);
 200  
             }
 201  2181
             nodeText = null;
 202  2181
         } else if (reference != null && current.isVulnReferencesNode()) {
 203  270
             vulnerability.addReference(reference);
 204  270
             reference = null;
 205  4158
         } else if (reference != null && current.isVulnReferenceNode()) {
 206  270
             reference.setName(nodeText.toString());
 207  270
             nodeText = null;
 208  3888
         } else if (reference != null && current.isVulnSourceNode()) {
 209  270
             reference.setSource(nodeText.toString());
 210  270
             nodeText = null;
 211  3618
         } else if (current.isVulnSummaryNode()) {
 212  81
             vulnerability.setDescription(nodeText.toString());
 213  81
             nodeText = null;
 214  
         }
 215  7236
     }
 216  
     /**
 217  
      * the cve database.
 218  
      */
 219  
     private CveDB cveDB;
 220  
 
 221  
     /**
 222  
      * Sets the cveDB.
 223  
      *
 224  
      * @param db a reference to the CveDB
 225  
      */
 226  
     public void setCveDB(CveDB db) {
 227  0
         cveDB = db;
 228  0
     }
 229  
     /**
 230  
      * A list of CVE entries and associated VulnerableSoftware entries that
 231  
      * contain previous entries.
 232  
      */
 233  
     private Map<String, List<VulnerableSoftware>> prevVersionVulnMap;
 234  
 
 235  
     /**
 236  
      * Sets the prevVersionVulnMap.
 237  
      *
 238  
      * @param map the map of vulnerable software with previous versions being
 239  
      * vulnerable
 240  
      */
 241  
     public void setPrevVersionVulnMap(Map<String, List<VulnerableSoftware>> map) {
 242  0
         prevVersionVulnMap = map;
 243  0
     }
 244  
 
 245  
     /**
 246  
      * Saves a vulnerability to the CVE Database. This is a callback method
 247  
      * called by the Sax Parser Handler
 248  
      * {@link org.owasp.dependencycheck.data.nvdcve.xml.NvdCve20Handler}.
 249  
      *
 250  
      * @param vuln the vulnerability to store in the database
 251  
      * @throws DatabaseException thrown if there is an error writing to the
 252  
      * database
 253  
      * @throws CorruptIndexException is thrown if the CPE Index is corrupt
 254  
      * @throws IOException thrown if there is an IOException with the CPE Index
 255  
      */
 256  
     public void saveEntry(Vulnerability vuln) throws DatabaseException, CorruptIndexException, IOException {
 257  54
         if (cveDB == null) {
 258  54
             return;
 259  
         }
 260  0
         final String cveName = vuln.getName();
 261  0
         if (prevVersionVulnMap.containsKey(cveName)) {
 262  0
             final List<VulnerableSoftware> vulnSoftware = prevVersionVulnMap.get(cveName);
 263  0
             for (VulnerableSoftware vs : vulnSoftware) {
 264  0
                 vuln.updateVulnerableSoftware(vs);
 265  
             }
 266  
         }
 267  0
         for (VulnerableSoftware vs : vuln.getVulnerableSoftware()) {
 268  0
             if (cpeIndex != null) {
 269  0
                 cpeIndex.saveEntry(vs);
 270  
             }
 271  
         }
 272  0
         cveDB.updateVulnerability(vuln);
 273  0
     }
 274  
     /**
 275  
      * the cpe index.
 276  
      */
 277  
     private Index cpeIndex;
 278  
 
 279  
     /**
 280  
      * Sets the cpe index.
 281  
      *
 282  
      * @param index the CPE Lucene Index
 283  
      */
 284  
     void setCpeIndex(Index index) {
 285  0
         cpeIndex = index;
 286  0
     }
 287  
 
 288  
     // <editor-fold defaultstate="collapsed" desc="The Element Class that maintains state information about the current node">
 289  
     /**
 290  
      * A simple class to maintain information about the current element while
 291  
      * parsing the NVD CVE XML.
 292  
      */
 293  3
     protected static class Element {
 294  
 
 295  
         /**
 296  
          * A node type in the NVD CVE Schema 2.0
 297  
          */
 298  
         public static final String NVD = "nvd";
 299  
         /**
 300  
          * A node type in the NVD CVE Schema 2.0
 301  
          */
 302  
         public static final String ENTRY = "entry";
 303  
         /**
 304  
          * A node type in the NVD CVE Schema 2.0
 305  
          */
 306  
         public static final String VULN_PRODUCT = "vuln:product";
 307  
         /**
 308  
          * A node type in the NVD CVE Schema 2.0
 309  
          */
 310  
         public static final String VULN_REFERENCES = "vuln:references";
 311  
         /**
 312  
          * A node type in the NVD CVE Schema 2.0
 313  
          */
 314  
         public static final String VULN_SOURCE = "vuln:source";
 315  
         /**
 316  
          * A node type in the NVD CVE Schema 2.0
 317  
          */
 318  
         public static final String VULN_REFERENCE = "vuln:reference";
 319  
         /**
 320  
          * A node type in the NVD CVE Schema 2.0
 321  
          */
 322  
         public static final String VULN_SUMMARY = "vuln:summary";
 323  
         /**
 324  
          * A node type in the NVD CVE Schema 2.0
 325  
          */
 326  
         public static final String VULN_CWE = "vuln:cwe";
 327  
         /**
 328  
          * A node type in the NVD CVE Schema 2.0
 329  
          */
 330  
         public static final String CVSS_SCORE = "cvss:score";
 331  
         /**
 332  
          * A node type in the NVD CVE Schema 2.0
 333  
          */
 334  
         public static final String CVSS_ACCESS_VECTOR = "cvss:access-vector";
 335  
         /**
 336  
          * A node type in the NVD CVE Schema 2.0
 337  
          */
 338  
         public static final String CVSS_ACCESS_COMPLEXITY = "cvss:access-complexity";
 339  
         /**
 340  
          * A node type in the NVD CVE Schema 2.0
 341  
          */
 342  
         public static final String CVSS_AUTHENTICATION = "cvss:authentication";
 343  
         /**
 344  
          * A node type in the NVD CVE Schema 2.0
 345  
          */
 346  
         public static final String CVSS_CONFIDENTIALITY_IMPACT = "cvss:confidentiality-impact";
 347  
         /**
 348  
          * A node type in the NVD CVE Schema 2.0
 349  
          */
 350  
         public static final String CVSS_INTEGRITY_IMPACT = "cvss:integrity-impact";
 351  
         /**
 352  
          * A node type in the NVD CVE Schema 2.0
 353  
          */
 354  
         public static final String CVSS_AVAILABILITY_IMPACT = "cvss:availability-impact";
 355  
         /**
 356  
          * The current node.
 357  
          */
 358  
         private String node;
 359  
 
 360  
         /**
 361  
          * Gets the value of node.
 362  
          *
 363  
          * @return the value of node
 364  
          */
 365  
         public String getNode() {
 366  0
             return this.node;
 367  
         }
 368  
 
 369  
         /**
 370  
          * Sets the value of node.
 371  
          *
 372  
          * @param node new value of node
 373  
          */
 374  
         public void setNode(String node) {
 375  14472
             this.node = node;
 376  14472
         }
 377  
 
 378  
         /**
 379  
          * Checks if the handler is at the NVD node.
 380  
          *
 381  
          * @return true or false
 382  
          */
 383  
         public boolean isNVDNode() {
 384  4083
             return NVD.equals(node);
 385  
         }
 386  
 
 387  
         /**
 388  
          * Checks if the handler is at the ENTRY node.
 389  
          *
 390  
          * @return true or false
 391  
          */
 392  
         public boolean isEntryNode() {
 393  14472
             return ENTRY.equals(node);
 394  
         }
 395  
 
 396  
         /**
 397  
          * Checks if the handler is at the VULN_PRODUCT node.
 398  
          *
 399  
          * @return true or false
 400  
          */
 401  
         public boolean isVulnProductNode() {
 402  13764
             return VULN_PRODUCT.equals(node);
 403  
         }
 404  
 
 405  
         /**
 406  
          * Checks if the handler is at the REFERENCES node.
 407  
          *
 408  
          * @return true or false
 409  
          */
 410  
         public boolean isVulnReferencesNode() {
 411  5784
             return VULN_REFERENCES.equals(node);
 412  
         }
 413  
 
 414  
         /**
 415  
          * Checks if the handler is at the REFERENCE node.
 416  
          *
 417  
          * @return true or false
 418  
          */
 419  
         public boolean isVulnReferenceNode() {
 420  1080
             return VULN_REFERENCE.equals(node);
 421  
         }
 422  
 
 423  
         /**
 424  
          * Checks if the handler is at the VULN_SOURCE node.
 425  
          *
 426  
          * @return true or false
 427  
          */
 428  
         public boolean isVulnSourceNode() {
 429  540
             return VULN_SOURCE.equals(node);
 430  
         }
 431  
 
 432  
         /**
 433  
          * Checks if the handler is at the VULN_SUMMARY node.
 434  
          *
 435  
          * @return true or false
 436  
          */
 437  
         public boolean isVulnSummaryNode() {
 438  7782
             return VULN_SUMMARY.equals(node);
 439  
         }
 440  
 
 441  
         /**
 442  
          * Checks if the handler is at the VULN_CWE node.
 443  
          *
 444  
          * @return true or false
 445  
          */
 446  
         public boolean isVulnCWENode() {
 447  4080
             return VULN_CWE.equals(node);
 448  
         }
 449  
 
 450  
         /**
 451  
          * Checks if the handler is at the CVSS_SCORE node.
 452  
          *
 453  
          * @return true or false
 454  
          */
 455  
         public boolean isCVSSScoreNode() {
 456  11178
             return CVSS_SCORE.equals(node);
 457  
         }
 458  
 
 459  
         /**
 460  
          * Checks if the handler is at the CVSS_ACCESS_VECTOR node.
 461  
          *
 462  
          * @return true or false
 463  
          */
 464  
         public boolean isCVSSAccessVectorNode() {
 465  11022
             return CVSS_ACCESS_VECTOR.equals(node);
 466  
         }
 467  
 
 468  
         /**
 469  
          * Checks if the handler is at the CVSS_ACCESS_COMPLEXITY node.
 470  
          *
 471  
          * @return true or false
 472  
          */
 473  
         public boolean isCVSSAccessComplexityNode() {
 474  10866
             return CVSS_ACCESS_COMPLEXITY.equals(node);
 475  
         }
 476  
 
 477  
         /**
 478  
          * Checks if the handler is at the CVSS_AUTHENTICATION node.
 479  
          *
 480  
          * @return true or false
 481  
          */
 482  
         public boolean isCVSSAuthenticationNode() {
 483  10710
             return CVSS_AUTHENTICATION.equals(node);
 484  
         }
 485  
 
 486  
         /**
 487  
          * Checks if the handler is at the CVSS_CONFIDENTIALITY_IMPACT node.
 488  
          *
 489  
          * @return true or false
 490  
          */
 491  
         public boolean isCVSSConfidentialityImpactNode() {
 492  10398
             return CVSS_CONFIDENTIALITY_IMPACT.equals(node);
 493  
         }
 494  
 
 495  
         /**
 496  
          * Checks if the handler is at the CVSS_INTEGRITY_IMPACT node.
 497  
          *
 498  
          * @return true or false
 499  
          */
 500  
         public boolean isCVSSIntegrityImpactNode() {
 501  10242
             return CVSS_INTEGRITY_IMPACT.equals(node);
 502  
         }
 503  
 
 504  
         /**
 505  
          * Checks if the handler is at the CVSS_AVAILABILITY_IMPACT node.
 506  
          *
 507  
          * @return true or false
 508  
          */
 509  
         public boolean isCVSSAvailabilityImpactNode() {
 510  10554
             return CVSS_AVAILABILITY_IMPACT.equals(node);
 511  
         }
 512  
     }
 513  
     // </editor-fold>
 514  
 }