##### Coverage Report - org.owasp.dependencycheck.data.nvdcve.NvdCve20Handler

Classes in this File | Line Coverage | Branch Coverage | Complexity
NvdCve20Handler |
76% | 97/126
84% | 73/86
| 3.0;3
NvdCve20Handler$Element |
94% | 18/19
N/A | N/A
| 3.0;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;
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.CpeIndexWriter;
28 |  |
     import org.owasp.dependencycheck.dependency.Reference;
29 |  |
     import org.owasp.dependencycheck.dependency.Vulnerability;
30 |  |
     import org.owasp.dependencycheck.dependency.VulnerableSoftware;
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 (jeremy.long@owasp.org)
40 |  |
      */
41 | 1 |
     public class NvdCve20Handler extends DefaultHandler {
42 |  |
43 |  |
         /**
44 |  |
          * the current supported schema version.
45 |  |
          */
46 |  |
         private static final String CURRENT_SCHEMA_VERSION = "2.0";
47 |  |
         /**
48 |  |
          * the current element.
49 |  |
          */
50 | 1 |
         private final Element current = new Element();
51 |  |
         /**
52 |  |
          * the text of the node.
53 |  |
          */
54 |  |
         private StringBuilder nodeText;
55 |  |
         /**
56 |  |
          * the vulnerability.
57 |  |
          */
58 |  |
         private Vulnerability vulnerability;
59 |  |
         /**
60 |  |
          * a reference for the cve.
61 |  |
          */
62 |  |
         private Reference reference;
63 |  |
         /**
64 |  |
          * flag indicating whether the application has a cpe.
65 |  |
          */
66 | 1 |
         private boolean hasApplicationCpe = false;
67 |  |
         /**
68 |  |
          * The total number of entries parsed.
69 |  |
          */
70 |  |
         private int totalNumberOfEntries;
71 |  |
72 |  |
         /**
73 |  |
          * Get the value of totalNumberOfEntries.
74 |  |
          *
75 |  |
          * @return the value of totalNumberOfEntries
76 |  |
          */
77 |  |
         public int getTotalNumberOfEntries() {
78 | 0 |
             return totalNumberOfEntries;
79 |  |
         }
80 |  |
         /**
81 |  |
          * The total number of application entries parsed.
82 |  |
          */
83 |  |
         private int totalNumberOfApplicationEntries;
84 |  |
85 |  |
         /**
86 |  |
          * Get the value of totalNumberOfApplicationEntries.
87 |  |
          *
88 |  |
          * @return the value of totalNumberOfApplicationEntries
89 |  |
          */
90 |  |
         public int getTotalNumberOfApplicationEntries() {
91 | 0 |
             return totalNumberOfApplicationEntries;
92 |  |
         }
93 |  |
94 |  |
         @Override
95 |  |
         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
96 | 2412 |
             current.setNode(qName);
97 | 2412 |
             if (current.isEntryNode()) {
98 | 27 |
                 hasApplicationCpe = false;
99 | 27 |
                 vulnerability = new Vulnerability();
100 | 27 |
                 vulnerability.setName(attributes.getValue("id"));
101 | 2385 |
             } else if (current.isVulnProductNode()) {
102 | 727 |
                 nodeText = new StringBuilder(100);
103 | 1658 |
             } else if (current.isVulnReferencesNode()) {
104 | 90 |
                 final String lang = attributes.getValue("xml:lang");
105 | 90 |
                 if ("en".equals(lang)) {
106 | 90 |
                     reference = new Reference();
107 |  |
                 } else {
108 | 0 |
                     reference = null;
109 |  |
                 }
110 | 90 |
             } else if (reference != null && current.isVulnReferenceNode()) {
111 | 90 |
                 reference.setUrl(attributes.getValue("href"));
112 | 90 |
                 nodeText = new StringBuilder(130);
113 | 1478 |
             } else if (reference != null && current.isVulnSourceNode()) {
114 | 90 |
                 nodeText = new StringBuilder(30);
115 | 1388 |
             } else if (current.isVulnSummaryNode()) {
116 | 27 |
                 nodeText = new StringBuilder(500);
117 | 1361 |
             } else if (current.isNVDNode()) {
118 | 1 |
                 final String nvdVer = attributes.getValue("nvd_xml_version");
119 | 1 |
                 if (!CURRENT_SCHEMA_VERSION.equals(nvdVer)) {
120 | 0 |
                     throw new SAXNotSupportedException("Schema version " + nvdVer + " is not supported");
121 |  |
                 }
122 | 1 |
             } else if (current.isVulnCWENode()) {
123 | 19 |
                 vulnerability.setCwe(attributes.getValue("id"));
124 | 1341 |
             } else if (current.isCVSSScoreNode()) {
125 | 26 |
                 nodeText = new StringBuilder(5);
126 | 1315 |
             } else if (current.isCVSSAccessVectorNode()) {
127 | 26 |
                 nodeText = new StringBuilder(20);
128 | 1289 |
             } else if (current.isCVSSAccessComplexityNode()) {
129 | 26 |
                 nodeText = new StringBuilder(20);
130 | 1263 |
             } else if (current.isCVSSAuthenticationNode()) {
131 | 26 |
                 nodeText = new StringBuilder(20);
132 | 1237 |
             } else if (current.isCVSSAvailabilityImpactNode()) {
133 | 26 |
                 nodeText = new StringBuilder(20);
134 | 1211 |
             } else if (current.isCVSSConfidentialityImpactNode()) {
135 | 26 |
                 nodeText = new StringBuilder(20);
136 | 1185 |
             } else if (current.isCVSSIntegrityImpactNode()) {
137 | 26 |
                 nodeText = new StringBuilder(20);
138 |  |
             }
139 | 2412 |
         }
140 |  |
141 |  |
         @Override
142 |  |
         public void characters(char[] ch, int start, int length) throws SAXException {
143 | 3987 |
             if (nodeText != null) {
144 | 1142 |
                 nodeText.append(ch, start, length);
145 |  |
             }
146 | 3987 |
         }
147 |  |
148 |  |
         @Override
149 |  |
         public void endElement(String uri, String localName, String qName) throws SAXException {
150 | 2412 |
             current.setNode(qName);
151 | 2412 |
             if (current.isEntryNode()) {
152 | 27 |
                 totalNumberOfEntries += 1;
153 | 27 |
                 if (hasApplicationCpe) {
154 | 18 |
                     totalNumberOfApplicationEntries += 1;
155 |  |
                     try {
156 | 18 |
                         saveEntry(vulnerability);
157 | 0 |
                     } catch (DatabaseException ex) {
158 | 0 |
                         throw new SAXException(ex);
159 | 0 |
                     } catch (CorruptIndexException ex) {
160 | 0 |
                         throw new SAXException(ex);
161 | 0 |
                     } catch (IOException ex) {
162 | 0 |
                         throw new SAXException(ex);
163 | 18 |
                     }
164 |  |
                 }
165 | 27 |
                 vulnerability = null;
166 | 2385 |
             } else if (current.isCVSSScoreNode()) {
167 |  |
                 try {
168 | 26 |
                     final float score = Float.parseFloat(nodeText.toString());
169 | 26 |
                     vulnerability.setCvssScore(score);
170 | 0 |
                 } catch (NumberFormatException ex) {
171 | 0 |
                     Logger.getLogger(NvdCve20Handler.class.getName()).log(Level.SEVERE, "Error parsing CVSS Score.");
172 | 0 |
                     Logger.getLogger(NvdCve20Handler.class.getName()).log(Level.FINE, null, ex);
173 | 26 |
                 }
174 | 26 |
                 nodeText = null;
175 | 2359 |
             } else if (current.isCVSSAccessVectorNode()) {
176 | 26 |
                 vulnerability.setCvssAccessVector(nodeText.toString());
177 | 26 |
                 nodeText = null;
178 | 2333 |
             } else if (current.isCVSSAccessComplexityNode()) {
179 | 26 |
                 vulnerability.setCvssAccessComplexity(nodeText.toString());
180 | 26 |
                 nodeText = null;
181 | 2307 |
             } else if (current.isCVSSAuthenticationNode()) {
182 | 26 |
                 vulnerability.setCvssAuthentication(nodeText.toString());
183 | 26 |
                 nodeText = null;
184 | 2281 |
             } else if (current.isCVSSAvailabilityImpactNode()) {
185 | 26 |
                 vulnerability.setCvssAvailabilityImpact(nodeText.toString());
186 | 26 |
                 nodeText = null;
187 | 2255 |
             } else if (current.isCVSSConfidentialityImpactNode()) {
188 | 26 |
                 vulnerability.setCvssConfidentialityImpact(nodeText.toString());
189 | 26 |
                 nodeText = null;
190 | 2229 |
             } else if (current.isCVSSIntegrityImpactNode()) {
191 | 26 |
                 vulnerability.setCvssIntegrityImpact(nodeText.toString());
192 | 26 |
                 nodeText = null;
193 | 2203 |
             } else if (current.isVulnProductNode()) {
194 | 727 |
                 final String cpe = nodeText.toString();
195 | 727 |
                 if (cpe.startsWith("cpe:/a:")) {
196 | 614 |
                     hasApplicationCpe = true;
197 | 614 |
                     vulnerability.addVulnerableSoftware(cpe);
198 |  |
                 }
199 | 727 |
                 nodeText = null;
200 | 727 |
             } else if (reference != null && current.isVulnReferencesNode()) {
201 | 90 |
                 vulnerability.addReference(reference);
202 | 90 |
                 reference = null;
203 | 1386 |
             } else if (reference != null && current.isVulnReferenceNode()) {
204 | 90 |
                 reference.setName(nodeText.toString());
205 | 90 |
                 nodeText = null;
206 | 1296 |
             } else if (reference != null && current.isVulnSourceNode()) {
207 | 90 |
                 reference.setSource(nodeText.toString());
208 | 90 |
                 nodeText = null;
209 | 1206 |
             } else if (current.isVulnSummaryNode()) {
210 | 27 |
                 vulnerability.setDescription(nodeText.toString());
211 | 27 |
                 nodeText = null;
212 |  |
             }
213 | 2412 |
         }
214 |  |
         /**
215 |  |
          * the cve database.
216 |  |
          */
217 |  |
         private CveDB cveDB;
218 |  |
219 |  |
         /**
220 |  |
          * Sets the cveDB.
221 |  |
          *
222 |  |
          * @param db a reference to the CveDB
223 |  |
          */
224 |  |
         public void setCveDB(CveDB db) {
225 | 0 |
             cveDB = db;
226 | 0 |
         }
227 |  |
         /**
228 |  |
          * A list of CVE entries and associated VulnerableSoftware entries that
229 |  |
          * contain previous entries.
230 |  |
          */
231 |  |
         private Map<String, List<VulnerableSoftware>> prevVersionVulnMap;
232 |  |
233 |  |
         /**
234 |  |
          * Sets the prevVersionVulnMap.
235 |  |
          *
236 |  |
          * @param map the map of vulnerable software with previous versions being
237 |  |
          * vulnerable
238 |  |
          */
239 |  |
         public void setPrevVersionVulnMap(Map<String, List<VulnerableSoftware>> map) {
240 | 0 |
             prevVersionVulnMap = map;
241 | 0 |
         }
242 |  |
243 |  |
         /**
244 |  |
          * Saves a vulnerability to the CVE Database.
245 |  |
          *
246 |  |
          * @param vuln the vulnerability to store in the database
247 |  |
          * @throws DatabaseException thrown if there is an error writing to the
248 |  |
          * database
249 |  |
          * @throws CorruptIndexException is thrown if the CPE Index is corrupt
250 |  |
          * @throws IOException thrown if there is an IOException with the CPE Index
251 |  |
          */
252 |  |
         private void saveEntry(Vulnerability vuln) throws DatabaseException, CorruptIndexException, IOException {
253 | 18 |
             if (cveDB == null) {
254 | 18 |
                 return;
255 |  |
             }
256 | 0 |
             final String cveName = vuln.getName();
257 | 0 |
             if (prevVersionVulnMap.containsKey(cveName)) {
258 | 0 |
                 final List<VulnerableSoftware> vulnSoftware = prevVersionVulnMap.get(cveName);
259 | 0 |
                 for (VulnerableSoftware vs : vulnSoftware) {
260 | 0 |
                     vuln.updateVulnerableSoftware(vs);
261 |  |
                 }
262 |  |
             }
263 | 0 |
             for (VulnerableSoftware vs : vuln.getVulnerableSoftware()) {
264 | 0 |
                 if (cpeIndex != null) {
265 | 0 |
                     cpeIndex.saveEntry(vs);
266 |  |
                 }
267 |  |
             }
268 | 0 |
             cveDB.updateVulnerability(vuln);
269 | 0 |
         }
270 |  |
         /**
271 |  |
          * the cpe index.
272 |  |
          */
273 |  |
         private CpeIndexWriter cpeIndex;
274 |  |
275 |  |
         /**
276 |  |
          * Sets the cpe index writer.
277 |  |
          *
278 |  |
          * @param index the CPE Lucene Index
279 |  |
          */
280 |  |
         public void setCpeIndex(CpeIndexWriter index) {
281 | 0 |
             cpeIndex = index;
282 | 0 |
         }
283 |  |
284 |  |
         // <editor-fold defaultstate="collapsed" desc="The Element Class that maintains state information about the current node">
285 |  |
         /**
286 |  |
          * A simple class to maintain information about the current element while
287 |  |
          * parsing the NVD CVE XML.
288 |  |
          */
289 | 1 |
         protected static class Element {
290 |  |
291 |  |
             /**
292 |  |
              * A node type in the NVD CVE Schema 2.0
293 |  |
              */
294 |  |
             public static final String NVD = "nvd";
295 |  |
             /**
296 |  |
              * A node type in the NVD CVE Schema 2.0
297 |  |
              */
298 |  |
             public static final String ENTRY = "entry";
299 |  |
             /**
300 |  |
              * A node type in the NVD CVE Schema 2.0
301 |  |
              */
302 |  |
             public static final String VULN_PRODUCT = "vuln:product";
303 |  |
             /**
304 |  |
              * A node type in the NVD CVE Schema 2.0
305 |  |
              */
306 |  |
             public static final String VULN_REFERENCES = "vuln:references";
307 |  |
             /**
308 |  |
              * A node type in the NVD CVE Schema 2.0
309 |  |
              */
310 |  |
             public static final String VULN_SOURCE = "vuln:source";
311 |  |
             /**
312 |  |
              * A node type in the NVD CVE Schema 2.0
313 |  |
              */
314 |  |
             public static final String VULN_REFERENCE = "vuln:reference";
315 |  |
             /**
316 |  |
              * A node type in the NVD CVE Schema 2.0
317 |  |
              */
318 |  |
             public static final String VULN_SUMMARY = "vuln:summary";
319 |  |
             /**
320 |  |
              * A node type in the NVD CVE Schema 2.0
321 |  |
              */
322 |  |
             public static final String VULN_CWE = "vuln:cwe";
323 |  |
             /**
324 |  |
              * A node type in the NVD CVE Schema 2.0
325 |  |
              */
326 |  |
             public static final String CVSS_SCORE = "cvss:score";
327 |  |
             /**
328 |  |
              * A node type in the NVD CVE Schema 2.0
329 |  |
              */
330 |  |
             public static final String CVSS_ACCESS_VECTOR = "cvss:access-vector";
331 |  |
             /**
332 |  |
              * A node type in the NVD CVE Schema 2.0
333 |  |
              */
334 |  |
             public static final String CVSS_ACCESS_COMPLEXITY = "cvss:access-complexity";
335 |  |
             /**
336 |  |
              * A node type in the NVD CVE Schema 2.0
337 |  |
              */
338 |  |
             public static final String CVSS_AUTHENTICATION = "cvss:authentication";
339 |  |
             /**
340 |  |
              * A node type in the NVD CVE Schema 2.0
341 |  |
              */
342 |  |
             public static final String CVSS_CONFIDENTIALITY_IMPACT = "cvss:confidentiality-impact";
343 |  |
             /**
344 |  |
              * A node type in the NVD CVE Schema 2.0
345 |  |
              */
346 |  |
             public static final String CVSS_INTEGRITY_IMPACT = "cvss:integrity-impact";
347 |  |
             /**
348 |  |
              * A node type in the NVD CVE Schema 2.0
349 |  |
              */
350 |  |
             public static final String CVSS_AVAILABILITY_IMPACT = "cvss:availability-impact";
351 |  |
             /**
352 |  |
              * The current node.
353 |  |
              */
354 |  |
             private String node;
355 |  |
356 |  |
             /**
357 |  |
              * Gets the value of node.
358 |  |
              *
359 |  |
              * @return the value of node
360 |  |
              */
361 |  |
             public String getNode() {
362 | 0 |
                 return this.node;
363 |  |
             }
364 |  |
365 |  |
             /**
366 |  |
              * Sets the value of node.
367 |  |
              *
368 |  |
              * @param node new value of node
369 |  |
              */
370 |  |
             public void setNode(String node) {
371 | 4824 |
                 this.node = node;
372 | 4824 |
             }
373 |  |
374 |  |
             /**
375 |  |
              * Checks if the handler is at the NVD node.
376 |  |
              *
377 |  |
              * @return true or false
378 |  |
              */
379 |  |
             public boolean isNVDNode() {
380 | 1361 |
                 return NVD.equals(node);
381 |  |
             }
382 |  |
383 |  |
             /**
384 |  |
              * Checks if the handler is at the ENTRY node.
385 |  |
              *
386 |  |
              * @return true or false
387 |  |
              */
388 |  |
             public boolean isEntryNode() {
389 | 4824 |
                 return ENTRY.equals(node);
390 |  |
             }
391 |  |
392 |  |
             /**
393 |  |
              * Checks if the handler is at the VULN_PRODUCT node.
394 |  |
              *
395 |  |
              * @return true or false
396 |  |
              */
397 |  |
             public boolean isVulnProductNode() {
398 | 4588 |
                 return VULN_PRODUCT.equals(node);
399 |  |
             }
400 |  |
401 |  |
             /**
402 |  |
              * Checks if the handler is at the REFERENCES node.
403 |  |
              *
404 |  |
              * @return true or false
405 |  |
              */
406 |  |
             public boolean isVulnReferencesNode() {
407 | 1928 |
                 return VULN_REFERENCES.equals(node);
408 |  |
             }
409 |  |
410 |  |
             /**
411 |  |
              * Checks if the handler is at the REFERENCE node.
412 |  |
              *
413 |  |
              * @return true or false
414 |  |
              */
415 |  |
             public boolean isVulnReferenceNode() {
416 | 360 |
                 return VULN_REFERENCE.equals(node);
417 |  |
             }
418 |  |
419 |  |
             /**
420 |  |
              * Checks if the handler is at the VULN_SOURCE node.
421 |  |
              *
422 |  |
              * @return true or false
423 |  |
              */
424 |  |
             public boolean isVulnSourceNode() {
425 | 180 |
                 return VULN_SOURCE.equals(node);
426 |  |
             }
427 |  |
428 |  |
             /**
429 |  |
              * Checks if the handler is at the VULN_SUMMARY node.
430 |  |
              *
431 |  |
              * @return true or false
432 |  |
              */
433 |  |
             public boolean isVulnSummaryNode() {
434 | 2594 |
                 return VULN_SUMMARY.equals(node);
435 |  |
             }
436 |  |
437 |  |
             /**
438 |  |
              * Checks if the handler is at the VULN_CWE node.
439 |  |
              *
440 |  |
              * @return true or false
441 |  |
              */
442 |  |
             public boolean isVulnCWENode() {
443 | 1360 |
                 return VULN_CWE.equals(node);
444 |  |
             }
445 |  |
446 |  |
             /**
447 |  |
              * Checks if the handler is at the CVSS_SCORE node.
448 |  |
              *
449 |  |
              * @return true or false
450 |  |
              */
451 |  |
             public boolean isCVSSScoreNode() {
452 | 3726 |
                 return CVSS_SCORE.equals(node);
453 |  |
             }
454 |  |
455 |  |
             /**
456 |  |
              * Checks if the handler is at the CVSS_ACCESS_VECTOR node.
457 |  |
              *
458 |  |
              * @return true or false
459 |  |
              */
460 |  |
             public boolean isCVSSAccessVectorNode() {
461 | 3674 |
                 return CVSS_ACCESS_VECTOR.equals(node);
462 |  |
             }
463 |  |
464 |  |
             /**
465 |  |
              * Checks if the handler is at the CVSS_ACCESS_COMPLEXITY node.
466 |  |
              *
467 |  |
              * @return true or false
468 |  |
              */
469 |  |
             public boolean isCVSSAccessComplexityNode() {
470 | 3622 |
                 return CVSS_ACCESS_COMPLEXITY.equals(node);
471 |  |
             }
472 |  |
473 |  |
             /**
474 |  |
              * Checks if the handler is at the CVSS_AUTHENTICATION node.
475 |  |
              *
476 |  |
              * @return true or false
477 |  |
              */
478 |  |
             public boolean isCVSSAuthenticationNode() {
479 | 3570 |
                 return CVSS_AUTHENTICATION.equals(node);
480 |  |
             }
481 |  |
482 |  |
             /**
483 |  |
              * Checks if the handler is at the CVSS_CONFIDENTIALITY_IMPACT node.
484 |  |
              *
485 |  |
              * @return true or false
486 |  |
              */
487 |  |
             public boolean isCVSSConfidentialityImpactNode() {
488 | 3466 |
                 return CVSS_CONFIDENTIALITY_IMPACT.equals(node);
489 |  |
             }
490 |  |
491 |  |
             /**
492 |  |
              * Checks if the handler is at the CVSS_INTEGRITY_IMPACT node.
493 |  |
              *
494 |  |
              * @return true or false
495 |  |
              */
496 |  |
             public boolean isCVSSIntegrityImpactNode() {
497 | 3414 |
                 return CVSS_INTEGRITY_IMPACT.equals(node);
498 |  |
             }
499 |  |
500 |  |
             /**
501 |  |
              * Checks if the handler is at the CVSS_AVAILABILITY_IMPACT node.
502 |  |
              *
503 |  |
              * @return true or false
504 |  |
              */
505 |  |
             public boolean isCVSSAvailabilityImpactNode() {
506 | 3518 |
                 return CVSS_AVAILABILITY_IMPACT.equals(node);
507 |  |
             }
508 |  |
         }
509 |  |
         // </editor-fold>
510 |  |
     }