Coverage Report - org.owasp.dependencycheck.data.update.nvd.NvdCve20Handler
 
Classes in this File Line Coverage Branch Coverage Complexity
NvdCve20Handler
80%
100/125
89%
75/84
3.04
NvdCve20Handler$Element
94%
18/19
N/A
3.04
 
 1  
 /*
 2  
  * This file is part of dependency-check-core.
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  *
 16  
  * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
 17  
  */
 18  
 package org.owasp.dependencycheck.data.update.nvd;
 19  
 
 20  
 import java.io.IOException;
 21  
 import java.util.List;
 22  
 import java.util.Map;
 23  
 import org.apache.lucene.index.CorruptIndexException;
 24  
 import org.owasp.dependencycheck.data.nvdcve.CveDB;
 25  
 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
 26  
 import org.owasp.dependencycheck.dependency.Reference;
 27  
 import org.owasp.dependencycheck.dependency.Vulnerability;
 28  
 import org.owasp.dependencycheck.dependency.VulnerableSoftware;
 29  
 import org.slf4j.Logger;
 30  
 import org.slf4j.LoggerFactory;
 31  
 import org.xml.sax.Attributes;
 32  
 import org.xml.sax.SAXException;
 33  
 import org.xml.sax.SAXNotSupportedException;
 34  
 import org.xml.sax.helpers.DefaultHandler;
 35  
 
 36  
 /**
 37  
  * A SAX Handler that will parse the NVD CVE XML (schema version 2.0).
 38  
  *
 39  
  * @author Jeremy Long
 40  
  */
 41  8
 public class NvdCve20Handler extends DefaultHandler {
 42  
 
 43  
     /**
 44  
      * The logger.
 45  
      */
 46  8
     private static final Logger LOGGER = LoggerFactory.getLogger(NvdCve20Handler.class);
 47  
     /**
 48  
      * the current supported schema version.
 49  
      */
 50  
     private static final String CURRENT_SCHEMA_VERSION = "2.0";
 51  
     /**
 52  
      * the current element.
 53  
      */
 54  8
     private final Element current = new Element();
 55  
     /**
 56  
      * the text of the node.
 57  
      */
 58  
     private StringBuilder nodeText;
 59  
     /**
 60  
      * the vulnerability.
 61  
      */
 62  
     private Vulnerability vulnerability;
 63  
     /**
 64  
      * a reference for the cve.
 65  
      */
 66  
     private Reference reference;
 67  
     /**
 68  
      * flag indicating whether the application has a cpe.
 69  
      */
 70  8
     private boolean hasApplicationCpe = false;
 71  
     /**
 72  
      * The total number of entries parsed.
 73  
      */
 74  
     private int totalNumberOfEntries;
 75  
 
 76  
     /**
 77  
      * Get the value of totalNumberOfEntries.
 78  
      *
 79  
      * @return the value of totalNumberOfEntries
 80  
      */
 81  
     public int getTotalNumberOfEntries() {
 82  0
         return totalNumberOfEntries;
 83  
     }
 84  
     /**
 85  
      * The total number of application entries parsed.
 86  
      */
 87  
     private int totalNumberOfApplicationEntries;
 88  
 
 89  
     /**
 90  
      * Get the value of totalNumberOfApplicationEntries.
 91  
      *
 92  
      * @return the value of totalNumberOfApplicationEntries
 93  
      */
 94  
     public int getTotalNumberOfApplicationEntries() {
 95  0
         return totalNumberOfApplicationEntries;
 96  
     }
 97  
 
 98  
     @Override
 99  
     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
 100  19296
         current.setNode(qName);
 101  19296
         if (current.isEntryNode()) {
 102  216
             hasApplicationCpe = false;
 103  216
             vulnerability = new Vulnerability();
 104  216
             vulnerability.setName(attributes.getValue("id"));
 105  19080
         } else if (current.isVulnProductNode()) {
 106  5816
             nodeText = new StringBuilder(100);
 107  13264
         } else if (current.isVulnReferencesNode()) {
 108  720
             final String lang = attributes.getValue("xml:lang");
 109  720
             if ("en".equals(lang)) {
 110  720
                 reference = new Reference();
 111  
             } else {
 112  0
                 reference = null;
 113  
             }
 114  720
         } else if (reference != null && current.isVulnReferenceNode()) {
 115  720
             reference.setUrl(attributes.getValue("href"));
 116  720
             nodeText = new StringBuilder(130);
 117  11824
         } else if (reference != null && current.isVulnSourceNode()) {
 118  720
             nodeText = new StringBuilder(30);
 119  11104
         } else if (current.isVulnSummaryNode()) {
 120  216
             nodeText = new StringBuilder(500);
 121  10888
         } else if (current.isNVDNode()) {
 122  8
             final String nvdVer = attributes.getValue("nvd_xml_version");
 123  8
             if (!CURRENT_SCHEMA_VERSION.equals(nvdVer)) {
 124  0
                 throw new SAXNotSupportedException("Schema version " + nvdVer + " is not supported");
 125  
             }
 126  8
         } else if (current.isVulnCWENode()) {
 127  152
             vulnerability.setCwe(attributes.getValue("id"));
 128  10728
         } else if (current.isCVSSScoreNode()) {
 129  208
             nodeText = new StringBuilder(5);
 130  10520
         } else if (current.isCVSSAccessVectorNode()) {
 131  208
             nodeText = new StringBuilder(20);
 132  10312
         } else if (current.isCVSSAccessComplexityNode()) {
 133  208
             nodeText = new StringBuilder(20);
 134  10104
         } else if (current.isCVSSAuthenticationNode()) {
 135  208
             nodeText = new StringBuilder(20);
 136  9896
         } else if (current.isCVSSAvailabilityImpactNode()) {
 137  208
             nodeText = new StringBuilder(20);
 138  9688
         } else if (current.isCVSSConfidentialityImpactNode()) {
 139  208
             nodeText = new StringBuilder(20);
 140  9480
         } else if (current.isCVSSIntegrityImpactNode()) {
 141  208
             nodeText = new StringBuilder(20);
 142  
         }
 143  19296
     }
 144  
 
 145  
     @Override
 146  
     public void characters(char[] ch, int start, int length) throws SAXException {
 147  31896
         if (nodeText != null) {
 148  9136
             nodeText.append(ch, start, length);
 149  
         }
 150  31896
     }
 151  
 
 152  
     @Override
 153  
     public void endElement(String uri, String localName, String qName) throws SAXException {
 154  19296
         current.setNode(qName);
 155  19296
         if (current.isEntryNode()) {
 156  216
             totalNumberOfEntries += 1;
 157  216
             if (hasApplicationCpe) {
 158  152
                 totalNumberOfApplicationEntries += 1;
 159  
                 try {
 160  152
                     saveEntry(vulnerability);
 161  0
                 } catch (DatabaseException ex) {
 162  0
                     throw new SAXException(ex);
 163  0
                 } catch (CorruptIndexException ex) {
 164  0
                     throw new SAXException(ex);
 165  0
                 } catch (IOException ex) {
 166  0
                     throw new SAXException(ex);
 167  152
                 }
 168  
             }
 169  216
             vulnerability = null;
 170  19080
         } else if (current.isCVSSScoreNode()) {
 171  
             try {
 172  208
                 final float score = Float.parseFloat(nodeText.toString());
 173  208
                 vulnerability.setCvssScore(score);
 174  0
             } catch (NumberFormatException ex) {
 175  0
                 LOGGER.error("Error parsing CVSS Score.");
 176  0
                 LOGGER.debug("", ex);
 177  208
             }
 178  208
             nodeText = null;
 179  18872
         } else if (current.isCVSSAccessVectorNode()) {
 180  208
             vulnerability.setCvssAccessVector(nodeText.toString());
 181  208
             nodeText = null;
 182  18664
         } else if (current.isCVSSAccessComplexityNode()) {
 183  208
             vulnerability.setCvssAccessComplexity(nodeText.toString());
 184  208
             nodeText = null;
 185  18456
         } else if (current.isCVSSAuthenticationNode()) {
 186  208
             vulnerability.setCvssAuthentication(nodeText.toString());
 187  208
             nodeText = null;
 188  18248
         } else if (current.isCVSSAvailabilityImpactNode()) {
 189  208
             vulnerability.setCvssAvailabilityImpact(nodeText.toString());
 190  208
             nodeText = null;
 191  18040
         } else if (current.isCVSSConfidentialityImpactNode()) {
 192  208
             vulnerability.setCvssConfidentialityImpact(nodeText.toString());
 193  208
             nodeText = null;
 194  17832
         } else if (current.isCVSSIntegrityImpactNode()) {
 195  208
             vulnerability.setCvssIntegrityImpact(nodeText.toString());
 196  208
             nodeText = null;
 197  17624
         } else if (current.isVulnProductNode()) {
 198  5816
             final String cpe = nodeText.toString();
 199  5816
             if (cpe.startsWith("cpe:/a:")) {
 200  4912
                 hasApplicationCpe = true;
 201  4912
                 vulnerability.addVulnerableSoftware(cpe);
 202  
             }
 203  5816
             nodeText = null;
 204  5816
         } else if (reference != null && current.isVulnReferencesNode()) {
 205  720
             vulnerability.addReference(reference);
 206  720
             reference = null;
 207  11088
         } else if (reference != null && current.isVulnReferenceNode()) {
 208  720
             reference.setName(nodeText.toString());
 209  720
             nodeText = null;
 210  10368
         } else if (reference != null && current.isVulnSourceNode()) {
 211  720
             reference.setSource(nodeText.toString());
 212  720
             nodeText = null;
 213  9648
         } else if (current.isVulnSummaryNode()) {
 214  216
             vulnerability.setDescription(nodeText.toString());
 215  216
             if (nodeText.indexOf("** REJECT **") >= 0) {
 216  8
                 hasApplicationCpe = true; //ensure we process this to delete the vuln
 217  
             }
 218  216
             nodeText = null;
 219  
         }
 220  19296
     }
 221  
     /**
 222  
      * the cve database.
 223  
      */
 224  
     private CveDB cveDB;
 225  
 
 226  
     /**
 227  
      * Sets the cveDB.
 228  
      *
 229  
      * @param db a reference to the CveDB
 230  
      */
 231  
     public void setCveDB(CveDB db) {
 232  0
         cveDB = db;
 233  0
     }
 234  
     /**
 235  
      * A list of CVE entries and associated VulnerableSoftware entries that contain previous entries.
 236  
      */
 237  
     private Map<String, List<VulnerableSoftware>> prevVersionVulnMap;
 238  
 
 239  
     /**
 240  
      * Sets the prevVersionVulnMap.
 241  
      *
 242  
      * @param map the map of vulnerable software with previous versions being vulnerable
 243  
      */
 244  
     public void setPrevVersionVulnMap(Map<String, List<VulnerableSoftware>> map) {
 245  0
         prevVersionVulnMap = map;
 246  0
     }
 247  
 
 248  
     /**
 249  
      * Saves a vulnerability to the CVE Database.
 250  
      *
 251  
      * @param vuln the vulnerability to store in the database
 252  
      * @throws DatabaseException thrown if there is an error writing to the 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  
     private void saveEntry(Vulnerability vuln) throws DatabaseException, CorruptIndexException, IOException {
 257  152
         if (cveDB == null) {
 258  152
             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  0
             }
 266  
         }
 267  0
         cveDB.updateVulnerability(vuln);
 268  0
     }
 269  
 
 270  
     // <editor-fold defaultstate="collapsed" desc="The Element Class that maintains state information about the current node">
 271  
     /**
 272  
      * A simple class to maintain information about the current element while parsing the NVD CVE XML.
 273  
      */
 274  8
     protected static class Element {
 275  
 
 276  
         /**
 277  
          * A node type in the NVD CVE Schema 2.0
 278  
          */
 279  
         public static final String NVD = "nvd";
 280  
         /**
 281  
          * A node type in the NVD CVE Schema 2.0
 282  
          */
 283  
         public static final String ENTRY = "entry";
 284  
         /**
 285  
          * A node type in the NVD CVE Schema 2.0
 286  
          */
 287  
         public static final String VULN_PRODUCT = "vuln:product";
 288  
         /**
 289  
          * A node type in the NVD CVE Schema 2.0
 290  
          */
 291  
         public static final String VULN_REFERENCES = "vuln:references";
 292  
         /**
 293  
          * A node type in the NVD CVE Schema 2.0
 294  
          */
 295  
         public static final String VULN_SOURCE = "vuln:source";
 296  
         /**
 297  
          * A node type in the NVD CVE Schema 2.0
 298  
          */
 299  
         public static final String VULN_REFERENCE = "vuln:reference";
 300  
         /**
 301  
          * A node type in the NVD CVE Schema 2.0
 302  
          */
 303  
         public static final String VULN_SUMMARY = "vuln:summary";
 304  
         /**
 305  
          * A node type in the NVD CVE Schema 2.0
 306  
          */
 307  
         public static final String VULN_CWE = "vuln:cwe";
 308  
         /**
 309  
          * A node type in the NVD CVE Schema 2.0
 310  
          */
 311  
         public static final String CVSS_SCORE = "cvss:score";
 312  
         /**
 313  
          * A node type in the NVD CVE Schema 2.0
 314  
          */
 315  
         public static final String CVSS_ACCESS_VECTOR = "cvss:access-vector";
 316  
         /**
 317  
          * A node type in the NVD CVE Schema 2.0
 318  
          */
 319  
         public static final String CVSS_ACCESS_COMPLEXITY = "cvss:access-complexity";
 320  
         /**
 321  
          * A node type in the NVD CVE Schema 2.0
 322  
          */
 323  
         public static final String CVSS_AUTHENTICATION = "cvss:authentication";
 324  
         /**
 325  
          * A node type in the NVD CVE Schema 2.0
 326  
          */
 327  
         public static final String CVSS_CONFIDENTIALITY_IMPACT = "cvss:confidentiality-impact";
 328  
         /**
 329  
          * A node type in the NVD CVE Schema 2.0
 330  
          */
 331  
         public static final String CVSS_INTEGRITY_IMPACT = "cvss:integrity-impact";
 332  
         /**
 333  
          * A node type in the NVD CVE Schema 2.0
 334  
          */
 335  
         public static final String CVSS_AVAILABILITY_IMPACT = "cvss:availability-impact";
 336  
         /**
 337  
          * The current node.
 338  
          */
 339  
         private String node;
 340  
 
 341  
         /**
 342  
          * Gets the value of node.
 343  
          *
 344  
          * @return the value of node
 345  
          */
 346  
         public String getNode() {
 347  0
             return this.node;
 348  
         }
 349  
 
 350  
         /**
 351  
          * Sets the value of node.
 352  
          *
 353  
          * @param node new value of node
 354  
          */
 355  
         public void setNode(String node) {
 356  38592
             this.node = node;
 357  38592
         }
 358  
 
 359  
         /**
 360  
          * Checks if the handler is at the NVD node.
 361  
          *
 362  
          * @return true or false
 363  
          */
 364  
         public boolean isNVDNode() {
 365  10888
             return NVD.equals(node);
 366  
         }
 367  
 
 368  
         /**
 369  
          * Checks if the handler is at the ENTRY node.
 370  
          *
 371  
          * @return true or false
 372  
          */
 373  
         public boolean isEntryNode() {
 374  38592
             return ENTRY.equals(node);
 375  
         }
 376  
 
 377  
         /**
 378  
          * Checks if the handler is at the VULN_PRODUCT node.
 379  
          *
 380  
          * @return true or false
 381  
          */
 382  
         public boolean isVulnProductNode() {
 383  36704
             return VULN_PRODUCT.equals(node);
 384  
         }
 385  
 
 386  
         /**
 387  
          * Checks if the handler is at the REFERENCES node.
 388  
          *
 389  
          * @return true or false
 390  
          */
 391  
         public boolean isVulnReferencesNode() {
 392  15424
             return VULN_REFERENCES.equals(node);
 393  
         }
 394  
 
 395  
         /**
 396  
          * Checks if the handler is at the REFERENCE node.
 397  
          *
 398  
          * @return true or false
 399  
          */
 400  
         public boolean isVulnReferenceNode() {
 401  2880
             return VULN_REFERENCE.equals(node);
 402  
         }
 403  
 
 404  
         /**
 405  
          * Checks if the handler is at the VULN_SOURCE node.
 406  
          *
 407  
          * @return true or false
 408  
          */
 409  
         public boolean isVulnSourceNode() {
 410  1440
             return VULN_SOURCE.equals(node);
 411  
         }
 412  
 
 413  
         /**
 414  
          * Checks if the handler is at the VULN_SUMMARY node.
 415  
          *
 416  
          * @return true or false
 417  
          */
 418  
         public boolean isVulnSummaryNode() {
 419  20752
             return VULN_SUMMARY.equals(node);
 420  
         }
 421  
 
 422  
         /**
 423  
          * Checks if the handler is at the VULN_CWE node.
 424  
          *
 425  
          * @return true or false
 426  
          */
 427  
         public boolean isVulnCWENode() {
 428  10880
             return VULN_CWE.equals(node);
 429  
         }
 430  
 
 431  
         /**
 432  
          * Checks if the handler is at the CVSS_SCORE node.
 433  
          *
 434  
          * @return true or false
 435  
          */
 436  
         public boolean isCVSSScoreNode() {
 437  29808
             return CVSS_SCORE.equals(node);
 438  
         }
 439  
 
 440  
         /**
 441  
          * Checks if the handler is at the CVSS_ACCESS_VECTOR node.
 442  
          *
 443  
          * @return true or false
 444  
          */
 445  
         public boolean isCVSSAccessVectorNode() {
 446  29392
             return CVSS_ACCESS_VECTOR.equals(node);
 447  
         }
 448  
 
 449  
         /**
 450  
          * Checks if the handler is at the CVSS_ACCESS_COMPLEXITY node.
 451  
          *
 452  
          * @return true or false
 453  
          */
 454  
         public boolean isCVSSAccessComplexityNode() {
 455  28976
             return CVSS_ACCESS_COMPLEXITY.equals(node);
 456  
         }
 457  
 
 458  
         /**
 459  
          * Checks if the handler is at the CVSS_AUTHENTICATION node.
 460  
          *
 461  
          * @return true or false
 462  
          */
 463  
         public boolean isCVSSAuthenticationNode() {
 464  28560
             return CVSS_AUTHENTICATION.equals(node);
 465  
         }
 466  
 
 467  
         /**
 468  
          * Checks if the handler is at the CVSS_CONFIDENTIALITY_IMPACT node.
 469  
          *
 470  
          * @return true or false
 471  
          */
 472  
         public boolean isCVSSConfidentialityImpactNode() {
 473  27728
             return CVSS_CONFIDENTIALITY_IMPACT.equals(node);
 474  
         }
 475  
 
 476  
         /**
 477  
          * Checks if the handler is at the CVSS_INTEGRITY_IMPACT node.
 478  
          *
 479  
          * @return true or false
 480  
          */
 481  
         public boolean isCVSSIntegrityImpactNode() {
 482  27312
             return CVSS_INTEGRITY_IMPACT.equals(node);
 483  
         }
 484  
 
 485  
         /**
 486  
          * Checks if the handler is at the CVSS_AVAILABILITY_IMPACT node.
 487  
          *
 488  
          * @return true or false
 489  
          */
 490  
         public boolean isCVSSAvailabilityImpactNode() {
 491  28144
             return CVSS_AVAILABILITY_IMPACT.equals(node);
 492  
         }
 493  
     }
 494  
     // </editor-fold>
 495  
 }